Julia: Серьезное отношение к конкатенации строк или предложение отказаться от *, ^ для конкатенации и повторения строк

Созданный на 27 апр. 2015  ·  179Комментарии  ·  Источник: JuliaLang/julia

Частота и ожесточенность дискуссий на эту тему требуют изменения. * и ^ были введены для строк еще тогда, когда язык не был таким строгим в отношении каламбура операторов и общего значения.

В качестве первого шага я предлагаю отказаться от этих двух методов для строковых операций.

В следующем обсуждении мы можем поговорить о возможности использования другого оператора (ов) для конкатенации / повторения. Было предложено просто использовать repeat без оператора, а также следующее для конкатенации строк:

  • ++ , как общий оператор конкатенации последовательностей
  • .. , аналогично Lua

Что следует учитывать:

  • Будет ли тот же оператор применяться к другим операциям конкатенации, таким как векторы или многомерные массивы? В таком случае, как он будет взаимодействовать с vcat / hcat ?
decision design strings

Самый полезный комментарий

Мы можем добавить ++ в качестве общего оператора конкатенации последовательностей в будущем, но похоже, что избавления от * и ^ для строк не произойдет. Я скажу, что меня больше не беспокоит "каламбур" на * , и я даже не думаю, что это больше каламбур - в абстрактной алгебре, умножении (представленном как * или сопоставление) часто используется как некоммутативная групповая операция над вещами, не являющимися числами. Основные проблемы здесь были связаны с тем, что ранее Char <: Number но операция * для Char была несовместима с * для Number . Теперь, когда Char не является подтипом Nubmer , это больше не проблема.

Все 179 Комментарий

+1, если вообще нет инфиксных операторов. Этот объект привлекает слишком много шума, и O (n) для конкатенации a * b * c * d ... не подходит.

Если есть обсуждение альтернатив, то +100 за перенос в список рассылки julia-infix-operator-debates .

+1, если вообще нет инфиксных операторов. Этот объект привлекает слишком много шума, и O (n) для a * b * c * d ... конкатенация не подходит.

+1 к этому

Если есть обсуждение альтернатив, то +100 за перенос в список рассылки julia-infix-operator-debates.

:смеющийся:

СМЕШНО. +1 на julia-infix-operator-debates .

(Мне лично будет грустно видеть такое использование * и ^ go ...)

Стефан недавно дал красивое и лаконичное объяснение того, почему он хочет, чтобы они ушли, я процитирую его здесь:

Моя проблема с * для конкатенации строк не в том, что люди находят это неожиданным, а в том, что это неуместное использование * универсальной функции, которая, как принято, означает численное умножение. Аргумент, что строки образуют моноид, довольно слаб, поскольку многие вещи образуют моноид, и мы обычно не используем * для них. В то время, когда я представил * для строк, мы были гораздо менее строги в отношении каламбура операторов - вспомните | и & для команд оболочки - со временем мы стали намного строже, и это хорошо. Это один из последних каламбуров, оставшихся в стандартной библиотеке. Причина, по которой ++ был бы лучше, не в том, что его было бы легче изучить (зависит от того, откуда вы), а в том, что оператор ++ в Julia однозначно означал бы конкатенацию последовательностей.

Обратите внимание, что каламбур оператора не является чисто академической проблемой. Угловой случай Char показывает, где каламбур может вызвать проблемы: люди могут разумно ожидать, что 'x' * 'y' даст либо «xy», либо 241. Из-за этого мы просто делаем обе эти операции без ошибок метода, но это будет Совершенно разумно позволить 'x' ++ 'y' производить "xy". Гораздо меньше случаев, когда 'x' * 'y' дает 241 или 'ñ', но операция конкатенации последовательностей действительно имеет смысл.

Я, со своей стороны, согласен с тем, что ++ как общий оператор concat последовательности является ясным и явным, и согласен с тем, что пример Char, приведенный Стефаном, является хорошим примером того, как это упрощает вещи, устраняя неоднозначность намерений пользователя.

Я не видел этого до того, как начал разглагольствовать в ничего не подозревающем последнем сорванном потоке списка рассылки, где я предложил julia-stringconcat вместо (лучшего) julia-infix-operator-debates . + INTMAX. Убейте инфиксные операторы.

Я действительно_ считаю, что вам следует избегать использования всего, что уже имеет значение (кроме конкатенации строк) в других основных языках мира.
Я потратил слишком много времени на обнаружение ошибок из-за того, что разработчики переходили между несколькими языками, которые чрезмерно использовали простые операторы, что означало разные вещи на разных языках
в разных контекстах.

1) Вам нужно что-то, что не имеет другого значения для векторов, потому что люди, которые
обрабатывать строки для жизни, ожидая, что сможете использовать строки как векторы символов
(и наоборот). Это исключит +, *, ^, & и ||.

2) Вам нужно что-то, что не запутаешь большинство программистов (не только числовые
вычислительный мир). Это исключает , <> (SQL и другие языки).
Я думаю, что ++ будет немного запутанным, но поскольку это унарный оператор в C / C ++ / Java и т. Д.,
и это был бы бинарный оператор, думаю, было бы хорошо.

3) Вам нужен простой инфиксный оператор, по крайней мере, для конкатенации, иначе вы будете вставлены с
тонны виртуальных помидоров от всех, кто занимается обработкой строк.

Я бы проголосовал за ++, он используется для конкатенации на достаточно популярном языке, например, Haskell,
он вызывает идею сложения строк вместе, то есть их конкатенации, и
не имеют другого значения для векторов / массивов и могут использоваться как общие
оператор конкатенации векторов / массивов, что тоже хорошо (согласно пункту 1 выше)

Я не думаю, что ++ как общий оператор конкатенации последовательностей особенно ясен. Возвращает ли "abc"++[1, 2, 3] :

  • "abc[1,2,3]"
  • "abc\x01\x02\x03"
  • ['a', 'b', 'c', 1, 2, 3]
  • ["abc", [1, 2, 3]]
  • MethodError

Если мы собираемся использовать оператор конкатенации строк, я бы предпочел, чтобы это был просто оператор конкатенации строк и ничего больше. (Кто-нибудь жаловался на отсутствие инфиксного оператора для других операций конкатенации последовательностей?)

Меня также устраивает отсутствие оператора конкатенации строк, но наличие такого оператора в большинстве других языков заставляет меня задуматься, не пропущу ли я его, если бы выполнял проекты с большим количеством строк, такие как веб-материалы. Меня устраивает отсутствие инфиксного оператора, если мы решим, что он нам не нужен, потому что интерполяция, как правило, более полезна, чем конкатенация, но если это потому, что числовые рабочие процессы не делают слишком много конкатенации, я бы дважды подумал.

Должна ли быть замена - решение, которое можно отложить. Можем ли мы хоть раз оставить проблему, связанную с конкатенацией строк, узко определенной?

Если мы собираемся ввести замену, я думаю, что имеет смысл отказаться от * и одновременно ввести замену, чтобы люди действительно могли использовать замену при обновлении своего кода.

@StefanKarpinski, вы также получите хорошее поведение "mystring" ++ '\u2000' , которое, к сожалению, не работает сейчас с "mystring" * '\u2000' .

@simonstr , для меня это имеет смысл, как для человека, который большую часть своего времени тратит на обработку строк ...

a = Vector{UInt8}[1,2,3]
"abc" ++ a
[97, 98, 99, 1, 2, 3]

(если вы объедините вектор со строкой (которая является неизменной), вы бы предпочли вернуть другой изменяемый вектор, вы всегда можете преобразовать его в неизменяемую строку с помощью UTF8String позже)

Затем этот вопрос перейдет в любую другую дискуссию по этому поводу. Сообщество уже установило, что не может справиться с этой темой. Это идеальный велосипедный навес, и есть из множества цветов на выбор.

Если меня это раздражает, то это потому, что я. Вот мой опыт. «Эй, ты не можешь склеить струны с помощью + ?» «Да, это потому, что мы используем * ». "Ой, тогда ладно". С этого момента я продолжил свою жизнь.

Так что нет, я не думаю, что нам следует обсуждать альтернативные инфиксные операторы в этом выпуске, потому что в этом случае мы никогда не добьемся прогресса.

Чтобы высказать свое мнение по этому поводу, я использовал языки, в которых оператор конкатенации строк был . , + , (пробел), _ и ++ . Когда я запустил julia и узнал, что _ был оператором concat, моей первой мыслью было cool, that makes sense , потому что мне никогда не нравились + . Единственный аргумент в пользу отказа от использования * мне нравится, - это тот, который дал @StefanKarpinski о двусмысленности между Char как целым числом и Char как строкой из 1 символа. Таким образом, кажется, что ++ в качестве оператора concat является разумным, хотя в этом случае мы должны дать ему четкую семантику. Три варианта универсального ++ (что он должен делать, если тип равен, кажется очевидным), которые мне кажутся разумными:

++(x,y) = ++(string(x),string(y))
++(x,y) = #MethodError
++(x,y) = ++(promote(x,y)...)

Где "продвижение" продвигает соответствующий тип контейнера. Последний вариант подразумевает

x = Uint8[1,2,3]
"abc"++x == Uint8['a','b','c',1,2,3]

@keno , я это неправильно, потому что 'a' - это Char, 32-битный тип.
Итак, ответ должен быть либо: UInt8 [97, 98, 99, 1, 2, 3], либо Char ['a', 'b', 'c', 'x01', 'x02', 'x03 ']

Я голосую за ++

На самом деле, если у вас есть ASCIIString, он может быть повышен до UInt8 [], но UTF8String (а также UTF16String и UTF32String) нужно будет повысить до Char [].

(и такое продвижение было бы очень полезно для моей обработки строк ...)

Эту проблему можно было бы назвать «Серьезное отношение к конкатенации строк».

неоднозначность между Char как целым числом и Char как строкой из 1 символа.

Сразу отмечу, что:

julia-0.4> Char <: Integer
false

julia-0.4> 'a' * 'b'
ERROR: MethodError: `*` has no method matching *(::Char, ::Char)
Closest candidates are:
  *(::Any, ::Any, ::Any)
  *(::Any, ::Any, ::Any, ::Any...)

так что нет, Char не является целым числом, и с тех пор его не было в серии 0.4, и поэтому нет никакой двусмысленности. String * Char вполне может вернуть объединенную строку и т. Д. Этот аргумент просто устарел.

Пожалуйста, давайте не будем подвергать себя более чем 200 комментариям, пока мы не почувствуем, что к ним относятся достаточно серьезно.

Может кто просто пиар? Я думаю, что все выступают за отказ от *, ^ (хотя бы для устранения ошибки списка рассылки). Оператор ++, похоже, набирает обороты, но сделать его универсальным, очевидно, сложно и неочевидно. Есть хитрая семантика (похожая на push! vs. append! ), плохая алгоритмическая сложность и нет явной потребности в других итерациях. Так что давайте просто заставим его хорошо работать со строками (и, возможно, с символами) и закончим.

@ScottPJones Конечно, я писал это в иллюстративных целях, поскольку Char s может конвертировать в Uint8 s, если они находятся в диапазоне. Согласен с проблемой продвижения UTF8String.

@jiahao : эту проблему можно было бы назвать «Серьезное отношение к конкатенации строк».

СМЕШНО.

Кто-нибудь готовится к пакетному заказу?

Думаю, мне бы хотелось, но могу ли я получить его с помощью ++ вместо * ?

Хорошо, извините. Продолжать наставления - это весело, но давайте будем сосредоточены. Давайте попробуем придумать минимальный набор функций, которые PR мог бы разумно реализовать:

  • Прекращение поддержки * и ^ для строк
  • Реализация ++ для строк на строках

Все, что обобщается на другие контейнеры, я думаю, мы можем хэшировать внутри PR.

Хочу с ++! : ухмыляясь:

@staticfloat : 100:: +1:

Если мы хотим провести реальное обсуждение «серьезного отношения к строкам», например, таких как проблемы производительности, связанные с попыткой сделать строки завершенными на 0, где мы можем это сделать? (подумайте об очень распространенной операции с подстрокой или срезом в строке ... с Джулией вам нужно каждый раз создавать новую строку)

если мы все равно столкнемся с обрывом строки, похоже, самое подходящее время также устранить $ .

моя следующая лучшая альтернатива тому, чтобы не вызывать поломки, вероятно, является версия без оператора (https://github.com/JuliaLang/julia/tree/jb/strjuxtapose)

+1 к устаревшим * и ^ для строк.

Я чувствую много неясности вокруг оператора ++. Прямо сейчас приятно, например, что "$a$b" и string(a,b) делают одно и то же. Это легко спутать с a++b . Как часто нужно объединять строку с массивом? Это странная операция, поскольку непонятно, к чему относятся элементы массива - это могут быть кодовые точки или необработанные данные.

Я не хочу даже участвовать в этом обсуждении, но я чувствую себя обязанным упомянуть одну возможность, которая возникала в прошлом (в какой-то момент даже был PR, реализующий ее): использование сопоставления для конкатенации строк. Вы бы написали следующее:

"foo"  "bar" # "foobar"
"foo"   bar  # "foo$bar"
 foo   "bar" # "$(foo)bar"
 foo "" bar  # "$foo$bar"

Раньше у этого был недостаток, заключающийся в отсутствии операторной формы, например, что вы могли перейти к reduce , но это уже не так, поскольку вы можете использовать перегрузку вызовов, чтобы сделать ""(args...) конкатенацию строк . Таким образом, вы могли бы написать reduce("", objs) и получить конкатенацию строковых характеристик коллекции объектов. Это можно обобщить следующим образом:

julia> call{S<:String}(str::S, args...) = join(args, str)
call (generic function with 934 methods)

julia> reduce("", [1,"foo",1.23])
"1foo1.23"

julia> reduce(",", [1,"foo",1.23])
"1,foo,1.23"

Если вы собираетесь прокомментировать то, что только что написал @StefanKarpinski , сначала прочтите # 2301.

@stefankarpinski Ух !!! Не было конца ошибкам в коде из приложений Multivalue / Pick, потому что они использовали сопоставление ... трудно сказать, что код действительно делал.
Кроме того, что происходит с аргументами макроса ... в Джулии важны пробелы, поэтому
<strong i="8">@foo</strong> "Scott" "Paul" "Jones" макросу, ожидающему 3 аргумента, просто начинает ломаться, верно?

@JeffBezanson Если мне нужно использовать Vector {UInt8} или Vector {Char} для изменяемых строк, чтобы выполнить мою обработку строк, тогда я действительно хотел бы иметь возможность объединить неизменяемую строку с одной из них ... как люди жалуются на то, что сейчас невозможно объединить строки и символы, это обе операции, которые часто выполняются.

Но что делает объединение строки с вектором {UInt8}? Что делать, если вектор содержит UTF-8?

@JeffBezanson Объединение с вектором (UInt8) и UTF8String, вероятно, должно быть ошибкой. Конкатенация с ASCIIString вполне подойдет (возврат Vector {UInt8}).
Конкатентация Vector {Char} с UTF8String должна возвращать Vector {Char} (т.е. сначала выполнить преобразование UTF8-> UTF32) ... для производительности я бы сначала проверил UTF8String, сколько логических символов, создайте вывод буфер, достаточно большой для обоих, затем скопируйте Vector {Char} и преобразуйте UTF8String прямо в буфер ...)

На самом деле, вероятно, было бы лучше использовать любые конкатенации с векторами, кроме, может быть, Vector {Char}, и иметь пакет изменяемых строк и добавлять туда методы для ++ ... Намного чище, IMO.

Да, я согласен, в противном случае все усложняется.

Я думаю, что было бы ужасным решением вообще не иметь никаких инфиксных операторов для конкатенации строк. Это должно быть признаком того, что почти каждый современный язык общего назначения решил определить некоторый инфиксный оператор для этой операции. И тот факт, что другие языки делают много разных_выборов для оператора, указывает на то, что не существует жестких соглашений, от которых мы отклоняемся на нашу опасность.

Я согласен с @pao в том, что байкшед из-за этого контрпродуктивен, и мне трудно понять, почему людей так сильно волнует написание этого слова. * легко привыкнуть, это не _это_ странно, а Char*Char встречается не так часто, чтобы о нем беспокоиться.

Последовательность a * b является псевдонимом для string(a, b) за исключением особого случая, когда a и b являются числовыми, о да, или числовыми массивами, тогда это означает умножить.

Было бы лучше дать цепочке строк собственный оператор, чтобы десугаринг всегда выполнялся. И если он не используется ни на каком другом языке, тогда это будет справедливо для всех, сделав всех одинаково несчастными :)

Это также упростило бы преобразование a op b op c op d в string(a,b,c,d) с очевидными последствиями для производительности. Таким образом, только string() нуждается в оптимизации производительности (поскольку на данный момент это очень общая функция).

++ - это хорошо. Что он делает для не-струнных, можно понять позже.

@stevengj 1) Почему вы предполагаете, что Char ++ Char не появляется достаточно часто, чтобы о чем беспокоиться?
Это то, что меня беспокоит в обсуждениях здесь ... Я вижу много слов «это просто не важно» ... но это всего лишь мнение, и у вас есть люди с опытом обработки строк, которые говорят вам, что это _is_ важный. 2) * довольно сбивает с толку многих людей, поскольку я бы сказал, что для большинства людей, выполняющих обработку строк, они сначала думают о повторении, а не о конкатенации. Я видел, как многие люди поднимали этот вопрос. 3) Возможно, количество негативных комментариев о * как об операторе конкатенации за годы, прошедшие с того, что я видел, должно было указывать на то, что это не лучшее решение, и его следовало пересмотреть в версиях 0.1 или 0.2. , а не тогда, когда люди хотят получить версию 0.4 ...

@simonster По поводу "abc"++[1, 2, 3] . Это хороший пример того, что символический оператор с точкой, унаследованный от Matlab, время от времени кусает нас. Для сравнения: оператор конкатенации в J / APL - это , и он поставляется с «семейством точечных операторов», различающихся срезами, с которыми оператор должен работать.

   'abc' , '123'
abc123

'abc' ,"0 '123'
a1
b2
c3

или даже

 'abc' ,"1 0 '123'
abc1
abc2
abc3

Это не касается вопроса о продвижении типа, к которому вы обратились.

_Edit: Аргх, я упустил шанс ничего не сказать_

@ScottPJones , многие другие языки, похоже, имеют инфиксные операторы конкатенации строк, но не операторы конкатенации символов. Я не вижу шума жалоб. Вы по-прежнему можете объединить символы, выполнив string(char1, char2) (или используя строки длины 1, как в Python), поэтому нет недостающей функциональности. Если вы посмотрите на существующий код на любом широко распространенном языке, количество использований конкатенации строк значительно превышает количество случаев конкатенации двух символов.

Утверждения о том, что конкатенация символов хоть сколько-нибудь важна или полезна, как конкатенация строк, просто неправдоподобны.

Всегда будут отрицательные комментарии о вариантах написания. (Люди, пришедшие из Python, всегда будут жаловаться, что нам нужно end вместо использования отступов.) Вкусы различаются, и некоторые люди с сильными чувствами могут наделать много шума. Если мы выберем ++ , я гарантирую, что новички по-прежнему будут жаловаться: «Почему вы не использовали + ? + намного легче обнаружить и интуитивно понятно, потому что меня используют к нему с языка _X_. "

Не то чтобы мне особенно нравились * ; Меня это просто не волнует. Мне кажется, что постоянная подмена кода из-за бессмысленных изменений правописания более губительна для Джулии, чем любая выгода, которую мы получим от замены одного символа на другой.

Помимо всего этого, ++ будет чрезвычайно болезненным с точки зрения обновления. Поскольку ++ настоящее время не анализируется как инфиксный оператор, не будет чистого способа поддерживать обратную совместимость с Compat - это будет обновление дня флага , требующее, чтобы каждый пакет использовал конкатенацию строк для fork в версии 0.3 и 0.4 (или используйте string(a,b) , полностью отказавшись от инфиксной конкатенации).

Дело в том, что постоянная подмена кода из-за бессмысленных изменений правописания более губительна для Джулии, чем любая выгода, которую мы получим от замены одного символа на другой.

Да, его следует изменять только один раз, от того, что есть сейчас, до конечного состояния (или без изменений, если это решение). Отказ от поддержки сейчас и добавление оператора позже, когда все изменили свой код на строку (a, b) или «$ a $ b», просто означают зло для пользователей.

и O (n) для a * b * c * d ... конкатенация не подходит.

Можете ли вы лучше, чем O (n), для конкатенации строк?

@stevengj Языки, которые я использовал (которые также активно используются при обработке строк), как правило, не имеют отдельного типа символов (M [UMPS], Pick, JavaScript, Lua, Python и многие другие ...), поэтому он никогда даже не возникает как проблема, и те, которые делают (Java, C ++), прекрасно справляются с конкатенацией строк с символами и символов с символами.
Я не знаю, какой существующий код вы просматривали, но в большей части кода, с которым я имел дело (как внутренний код, так и код для тысяч клиентов), конкатенация символов с символами и со строками была сильно проделана. (и специально оптимизированы из-за того, как часто это делалось) [и только один из этих клиентов отвечает примерно за 54% медицинских записей в США].
Это не «бессмысленное изменение орфографии», довольно много людей выдвинули ряд серьезных возражений против использования * для конкатенации строк ... если бы это не раздражало людей серьезно, вы бы не видели этот разговор постоянно подойти.
Если вы не используете его так часто и не особо заботитесь о нем, а люди, которые хотят выполнять обработку строк в Julia, видят в этом серьезную проблему, почему вы так возражаете?
Я никогда не выступал за изменение * на что-то другое, основанное на вкусе, или потому что какой-то другой язык делает это иначе, мои аргументы были о: путанице (люди более склонны думать о повторении ... (* означает делать множественные числа что-то!), отсутствие согласованности с векторами (что является проблемой для людей, которые много обрабатывают строки, мы склонны думать о строках как о векторах символов) и проблемы с последовательным использованием Char (Char * Char, который имеет был удален, но как насчет других числовых операторов с Char? Иногда Char действует как UInt32, иногда нет ...)

Pick, например, использует односимвольные «системные разделители», обозначаемые такими вещами, как @RM , @VM , @FM , @SVM. .. (запись, значение , файл, метки подзначений), поэтому вы увидите "Scott":<strong i="9">@SVM</strong>:"Jones":<strong i="10">@VM</strong>:1:<strong i="11">@SVM</strong>:"Memorial":<strong i="12">@SVM</strong>:"Drive" , чтобы создать запись, которая в JSON, вероятно, будет выглядеть как [["Scott","Jones"],["1","Memorial","Drive"]] .
При паротите это делается следующим образом:
"Scott"_$c(1)_"Jones"_$c(0)_1_$c(1)_"Memorial"_$c(1)_"Drive"
(но на практике вы бы использовали макрос для $c(0) и $c(1) , например $$$subdlm и $$$valdlm ... они такие же, как Char(0) и Char(1) в Юлии)
И да, также есть много мест, где это объединение нескольких символов ... в M [umps] есть синтаксис $char(codepoint,...) , поэтому вы можете иметь $c(1,a,1,b,2,c) ... [ где a, b, c оцениваются как целые числа, т.е. кодовые точки).

@simonbyrne Я даже не понимаю, почему кто-то сказал, что
(но, возможно, именно так в Джулии, еще один признак того, что обработка строк попросту не воспринималась всерьез)

Данные конкатенации строк из самых популярных языков программирования :

  • Python: + , без объединения символов (или типа символа)
  • Perl: . , без символа
  • Рубин: + , без символа
  • C ++: + для строк, и для символов (но только для string + char, а не char + char)
  • Fortran: // (символы и строки с длиной 1 рассматриваются как взаимозаменяемые)
  • Go: + , без объединения символов
  • Haskell: ++ , без объединения символов (но добавляется через : )
  • Java: + , без объединения символов (очевидно, существует, но плохо документировано)
  • Цель C: нет оператора конкатенации (и много жалоб в Интернете)
  • C #: + для строк и символов (16-битные символы "юникода")
  • JavaScript: + , без символа
  • Паскаль: + , конкатенация символов (очевидно, существует в некоторых версиях Паскаля) плохо документирована
  • Visual Basic: + и & , символьное объединение очевидно существует, но плохо документировано

Вывод: инфиксный оператор конкатенации строк полезен, и если мы изменим что-либо, это должно быть + - это преобладающее соглашение, хотя и не универсальное. По крайней мере, обратную / прямую совместимость будет легко реализовать (две строчки в Compat.jl). Но это простое изменение орфографии, которое добавляет нулевую функциональность и сохраняет нулевые символы кода ценой большого количества оттока кода, поэтому я сомневаюсь в его полезности.

Кроме того, данные показывают, что перегрузка значения конкатенации арифметической операцией не является серьезной проблемой: люди, кажется, легко привыкают к ней и продолжают применять ее на новых языках.

И данные показывают, что синтаксис для конкатенации символов не является важной проблемой - многие языки, обычно используемые для обработки строк, даже не имеют символьного типа, а многие языки, у которых есть символьный тип, либо не имеют символьный + строка или char + char. конкатенации, или, если они это сделают, они не заботятся о ее хорошем документировании. Если вы выполняете много конкатенации символов во внутренних циклах, вам, вероятно, все равно понадобится более специализированный код, а если он не в критичном к производительности коде, вы всегда можете использовать строки string или длины 1.

(В любом случае, поскольку Char больше не является подтипом Integer в версии 0.4, при желании мы всегда можем добавить оператор конкатенации символов в будущем. Или вы можете добавить его самостоятельно в вашей собственной программе, если это важная операция в каком-то специализированном сценарии использования. Вся суть дизайна Джулии состоит в том, что «встроенные» функции обычно не имеют особого преимущества в производительности по сравнению с пользовательским кодом.)

@ScottPJones , если он выделяет новую непрерывную строку, a * b * c * d обязательно равно Ω (n), где n - общее количество символов, потому что он должен коснуться всех данных. Вы можете добиться большего только в том случае, если он создаст « веревочную строку » или подобную структуру данных, которая фактически не копирует данные, но имеет свои недостатки (последующие операции могут быть медленнее). По умолчанию выделение новой непрерывной строки вряд ли является «сумасшествием», и на самом деле это похоже на то, что по умолчанию используется на любом другом языке.

Я не думаю, что есть какая-то проблема с a * b * c , по крайней мере, не больше, чем с string(a,b,c) , так как это переведено на это :

julia-0.4> <strong i="9">@which</strong> "a" * "b" * "c"
*(s::AbstractString...) at string.jl:77

Тем не менее, я на 100% согласен с @stevengj, поэтому оставлю все как есть.

Тем не менее, я на 100% согласен с @stevengj, поэтому оставлю все как есть.

: +1:

В случае, если это было неясно, в то время как другие могут возражать против * на том основании, что это необычно или неожиданно для программистов, пришедших с других языков, меня это НЕ беспокоит - это не причина, по которой мне не нравится * . Меня _ только_ беспокоит то, что это злоупотребление значением общей функции * . Другими словами, действительно ли конкатенация строк является формой умножения? Соответственно, я категорически против использования + для конкатенации строк, независимо от того, сколько языков может его использовать: это явное и вопиющее злоупотребление значением функции + - ни в коем случае. является конкатенацией строк формой сложения.

@stevengj Это ваш вывод ... Я категорически не согласен с тем, что это должно быть + , во всяком случае, по многим из тех же причин, по которым * является проблемой в Джулии, поскольку он вызывает много проблем при работе с символами и возможности действовать одинаково для строк и векторов.
Однако ваши данные неверны, + для Java отлично работает с символом, и VB тоже (попробуйте их, если вы мне не верите! [И это _is_ задокументировано])
В Haskell просто введите string ++ [ch] или [ch] ++ string.
Паскаль тоже отлично работает (могу прислать вам пример)
Итак, для Python, Perl, Ruby, C ++, Java, C #, JavaScript, VB, Fortran, Haskell, Pascal у всех нет проблем с объединением символов ...
(также вы видите, что языки, которые действительно больше ориентированы на обработку строк, обычно _не__ имеют отдельный тип символа и только одну строку длиной 1, как языки, над которыми я работал, где все было строкой ...)
Остается Go & Objective C, что немного усложняет задачу ...
Я думаю, вы совершенно неверно истолковываете «данные» ... дело не в том, что конкатенация символов не является важной проблемой, просто в том, что для подавляющего большинства языков она обрабатывается, работает так, как ожидалось, и поэтому вы не получаете все жалобы, которые вы получаете на Юлию.

Python, Perl и Ruby не имеют символьного типа.

@simonbyrne Извините, я неправильно это понял ... Я думал об O (n ^ 2), это то, что я видел в Джулии в последнее время ... (потому что строки неизменяемы, и если у вас есть цикл, создающий строка, он выделяет тонну памяти и тратит много времени на сборку мусора ...)

так что вы не получите всех жалоб на Джулию.

Он попадает в списки рассылки

@StefanKarpinski Это было частью моей точки зрения, что языки, ориентированные на обработку строк, не имеют специального типа символа, символ - это просто строка длиной 1 ... (или Haskell, где строки на самом деле не особенные, они просто [char].

потому что строки неизменяемы, и если у вас есть цикл, создающий строку, он выделяет тонну памяти и тратит много времени на сборку мусора

Вы не хотите этого делать. Вместо этого вы должны печатать в объект IOBuffer, а затем брать строку в конце. Это похоже на шаблон StringBuilder в Java.

Стефан может закончить, как и все лидеры C ++: они громко заявляют, что использование беззнаковых целых чисел для индексации std :: vector было их серьезной ошибкой, но все же большинство программистов на C ++ по-прежнему считают, что это то, что делает C ++ таким приятным. К Юлии идет слава ;-)

Кстати, голосую за ++.

@ScottPJones , тогда это плохо документировано, если вы не можете найти документацию за 10 минут поиска в Google по "языку конкатенации символов X". (В общем, если вы ищете «конкатенированные строки» или «конкатенированные символы», сразу становится очевидным, что из них больше волнует.)

@stevengj Умм ... для людей, которым это

Это немного похоже на взлом, но чтобы позволить Compat обрабатывать ++ он может искать такой тип AST-шаблона:

julia> :('x'++'y') |> dump
Expr
  head: Symbol call
  args: Array(Any,(3,))
    1: Symbol +
    2: Char x
    3: Expr
      head: Symbol call
      args: Array(Any,(2,))
        1: Symbol +
        2: Char y
      typ: Any
  typ: Any

Также доступен оператор .. . Кажется, никому не нравится сопоставление / "" для объединения.

screen shot 2015-04-28 at 11 54 56 am

@StefanKarpinski , если вас не беспокоит вопрос знакомства, я сомневаюсь в философском пуризме точки зрения « + и * предназначены только для арифметики». Это языковой вопрос, следовательно, вопрос _конференции_, а не _ правильности_, ​​и _ подавляющее большинство_ компьютерных языков используют арифметический символ для конкатенации строк без видимых проблем. Люди к этому привыкли.

Обсуждение характера является касательной. Если бы у нас был оператор конкатенации строк, я абсолютно согласен, что он должен обрабатывать и символы.

Вы не хотите этого делать. Вместо этого вы должны печатать в объект IOBuffer, а затем брать строку в конце. Это похоже на шаблон StringBuilder в Java.

@StefanKarpinski Это именно то, что вам нужно сделать в Java или Julia для повышения производительности из-за неизменяемых строк ... это не значит, что им легко пользоваться или что люди сначала поймут, почему Юлия такая медленная по сравнению чтобы Python делал что-то вроде создания строки ...
(По этой причине мне тоже не нравится Java для обработки строк)

@StefanKarpinski , Compat не может искать этот шаблон AST, потому что тогда он x + +y где x и y - числа. Конечно, это случается нечасто, но мне не хотелось бы, чтобы @compat выполнял преобразование, которое потенциально может привести к неправильному коду.

Разве строки Python не являются неизменными?

@ScottPJones Я много лет преподаю математику. Гугл говорит глупости.

Плюс +: в математике принято, что + всегда является коммутативным оператором.
Времена *: в математике принято, что * может быть коммутативным (как с числами) или некоммутативным (как с матрицами). Вот почему у нас есть коммутативные и некоммутативные кольца.

Теперь, если мы вернемся к этому виду аргументов, вам следует прекратить использовать + для добавления плавающих точек, потому что + не ассоциативен с плавающими точками. И + всегда ассоциативен в математике. Это просто для того, чтобы показать вам, что этот «некоммутативный» аргумент для предотвращения использования + do concatenate strings не работает. Я предпочитаю ++, но считаю, что аргументы алгебры не должны входить в эту игру.

Кажется, никому не нравится сопоставление / "" для объединения.

Пустое пространство уже перегружено. Это будет конфликтовать с контекстами macro / hcat. Это подводит меня к вопросу, который я поднял на ML:

У Джулии уже есть два оператора конкатенации, а именно h - и vcat . Почему бы не использовать hcat для конкатенации строк в стиле MATLAB? Есть ли смысл строить матрицу строк?

Как бы то ни было ( .. , ++ , [ ... ] ), я выступаю за явный, отдельный оператор конкатенации для строк и символов.

Мы могли бы добавить ++ в качестве оператора к 0.4, а затем сделать отказ от поддержки, когда мы находимся на 0.5-dev. Здесь действительно спешат?

Fortran: // (символы и строки длины 1 считаются взаимозаменяемыми)

кажется хорошим «рациональным» вариантом для Юлии [1].

Я ожидал, что построение строки с * / string будет примерно O (n * m) по количеству соединяемых строк (n) и общему количеству соединяемых символов (m) . Какой-то объект построителя строк (cStringIO в python, StringBuilder / StringBuffer в Java, IOBuffer в Julia) необходим для хорошей производительности при создании чего-либо большого.


[1] для контекста:

> typeof(1//2)
Rational

Аргумент пуриста здесь напоминает мне фиаско с .+ для массива + скаляр. Когда философский пуризм сталкивается с лингвистической условностью и практичностью, пуризм проигрывает.

Ах, хорошее обсуждение построения строки O (n ^ 2) и такого re: python: http://stackoverflow.com/questions/4435169/good-way-to-append-to-a-string

Мне нравится решение построить список или массив с последующим вызовом join при необходимости.

Я знаю, что люди все время строят струны, но, похоже, этого следует избегать. Если это для ввода-вывода (обычно так), вы, очевидно, получите даже лучшую производительность, выполняя ввод-вывод напрямую, вместо того, чтобы сначала создавать строку, а затем отправлять ее. Даже такие вещи, как оптимизированный append cPython, только _amortized_ O (n), и вы, вероятно, откажетесь в 2 раза или около того.

@mbauman Мне это кажется разумным, по крайней мере.

+1 к предложению @mbauman . Кажется, что все в порядке с ++ и наличие общего оператора concat последовательности весьма привлекательно.

Предполагая, что вводится ++ , я думаю, что замечания @stevengj о Compat довольно убедительно указывают на то, что * не может быть устаревшим в версии 0.4.

@vtjnash // имеет ту же проблему, что уже имеет значение в Джулии как бинарный оператор ... чего, я думаю, было бы неплохо избежать ...

Поскольку мы разрабатываем жалобы по спискам рассылки, имейте в виду, что мы еще не слышали от всех тех, кто ожидает, что ++ будет оператором увеличения.

Я не думаю, что когда-либо говорил, что * for concat должен быть немедленно устаревшим, просто он должен быть где-то после .. или ++ или что-то еще

@JeffBezanson Вот почему я предпочел Lua .. , но, похоже, большинство людей предпочли бы увидеть ++ .
Я также считаю, что это не имеет большого значения, потому что один является унарным, а другой - двоичным.
(точно так же, как DataFrames перегружены ~)

@JeffBezanson Когда я запустил простой тест построения строк на Python и Julia, сразу после того, как я впервые загрузил Julia в прошлом месяце, я увидел, что он был более чем в 800 раз медленнее, чем Python, и сделал ошибочное предположение, что это означает, что строки изменяемы. Свинка, изменчивый и неизменный никогда не возникнет, потому что нет никаких ссылок на вещи, у вас просто есть значения, хранящиеся в ассоциативных массивах, в памяти или на диске, ничего больше. Я проделал те же виды оптимизации, которые, кажется, сделал CPython (с подсчетом ссылок на большие строки, копирование при записи под капотом).

@ScottPJones , превращение S=""; for s in list; S*=s; end в операцию O (n) для неизменяемых строк вместо O (n ^ 2) сильно отличается от обсуждаемого здесь; могу я попросить сосредоточиться?

@stevengj Это были @timholy и @johnmyleswhite, которые подняли O (n) ... и я, к сожалению, неправильно интерпретировал это как O (n ^ 2), что я видел для построения строк по сравнению с другими языками, такими как Python. .. моя ошибка!

Возможно, я неправильно понимаю, но похоже, что проблема возникла не потому, что у многих людей есть проблемы с конкатенацией строк в Джулии, как сейчас, а потому, что многим надоели повторяющиеся дискуссии, особенно последняя, ​​которая продолжалась какое-то время . Однако в данном случае я не уверен, что эта проблема связана с Юлией _per se_ в техническом смысле.

Я перечитал несколько предыдущих дискуссий, и ни одна из них не разделяет тон последней . Большинство из них очень дружелюбны: люди не могут вычислить конкатенацию строк, спросить в списке, узнать о * , возможно, спросить о его истории / обосновании, а затем вообще двигаться дальше.

Если беспокоят обсуждения, а не сам выбор оператора, возможно, с этим можно справиться без изменения языка, по крайней мере, на данный момент. Часто задаваемые вопросы могут объяснить ситуацию и предложить новых пользователей воздержаться от открытия проблемы на некоторое время.

ИМО, это было бы наименее затратным решением с точки зрения битого кода и часов программиста.

Эта беседа повышает мое кровяное давление, что является нелегкой задачей, но я чувствую, что поскольку это обсуждение типа design-by-mailing-list , я просто хочу отбросить свой вес (изо дня в день, использующий Джулию) почти во всем @stevengj говорит. Я думаю, что изменение оператора на ++ в порядке, но это просто вызовет новый виток стенаний, что это не просто + (и что это похоже на приращение), как указывает @JeffBezanson из. Я не понимаю проблемы с string * char учитывая, что char s больше не являются целыми числами - есть ли в этом проблема?

Если оператор должен смениться , понимает график. Думаю, это должно быть:

  1. Добавьте в качестве альтернативы * сейчас. Никто, кто поддерживает 0.3 и 0.4, не может его использовать. Добавление предупреждения об устаревании для *(string,string) было бы неуместным, так как любой, кто использует 0.4 с пакетом, пытающимся поддерживать 0.3, столкнется с ними.
  2. Выходит 0.4. Пакеты начинают смещение с 0,3 / 0,4 на 0,4 / 0,5
  3. Для 0.5 добавлено предупреждение об устаревании, поэтому пакеты, поддерживающие только 0.4 и 0.5, могут перейти на ++ .
  4. 0,5 выходит. Удалите * из 0.6.

Это действительно того стоит?

Добавление оператора конкатенации последовательностей, которого у нас просто нет, - законная идея. Очевидно, что * не будет использоваться для добавления списков или массивов. Однако, возможно, наличие оператора вызывает слишком много циклов O (n ^ 2) x ++= y . Технически синтаксис и производительность ортогональны, но на практике синтаксис может иметь такой эффект.

@IainNZ Я не думаю, что это правда, что Char больше не являются целыми числами, просто были удалены некоторые операции (*, / и ^), но я думаю, что это просто создает другие проблемы с несогласованностью ... т.е. почему + и - работают, а не * ...)

@ScottPJones

julia> Char <: Integer
false

РЕДАКТИРОВАТЬ: ... и я с @IainNZ по поводу артериального давления.

@JeffBezanson ++ = y не будет приглашать циклы O (n ^ 2) больше, чем * = y в настоящее время, и может дать компилятору больше шансов оптимизировать это, возможно?

@pao , правильно, я заметил, что * перестало работать между 0,3 и 0,4, а что +/- все еще работает ... так что они, должно быть, были добавлены специально для типа Char?

Меня больше беспокоит распространение проблемы на другие типы, если предположить, что ++ поддерживает массивы и списки.

Теперь мы рассматриваем Char как порядковый тип.

@JeffBezanson Я бы сказал, вы не можете помешать людям делать глупости ... попробуйте дать им хорошие инструменты, чтобы облегчить их жизнь, и постарайтесь предупредить их, что да, но не меняйте, потому что некоторые люди могут злоупотреблять этим ...

Думаю, мои опасения почти полностью развеялись бы, если бы у нас не было оператора ++= . Многие люди предполагают, и я действительно не могу их винить, что такой оператор, как += , мутирует.

Имея оператора, возможно, вам будет проще оптимизировать такие вещи, как CPython ...

На самом деле нецелесообразно оптимизировать S=""; for s in list; S*=s; end например CPython, независимо от написания. У Джулии нет счетчика ссылок, поэтому функция *(S,s) может знать, что она имеет единственную ссылку на S и, следовательно, S можно безопасно изменять. В некоторых случаях компилятор, конечно, мог бы это выяснить, но основная идея дизайна Джулии заключается в том, что он не отдает предпочтение встроенным типам над типами, определяемыми пользователем. Более того, волшебная оптимизация компилятора значительно усложняет рассуждение о производительности кода и _предсказуемо_ дизайн_ кода для обеспечения хорошей производительности (см. CPython и PyPy). Оператор ++= ничего не изменит в этом, и, как говорит @JeffBezanson, он, вероятно, побудит людей также чрезмерно использовать конкатенацию массивов. См. Также обсуждение в # 7052.

В любом случае я не считаю большой проблемой то, что оптимальная структура кода в Julia немного отличается от оптимальной структуры кода в CPython. Было бы большой проблемой, если бы в Julia было намного труднее получить хорошую производительность, чем в CPython, но join(list) не особо сложен / запутан и не записывает в IOBuffer() .

Также обратите внимание, что Джулия не является чем-то необычным в том, что повторная конкатенация равна O (n ^ 2); см., например, Ruby или Go . Тот факт, что конкатенация (в отличие, например, от append! ) никогда не изменяется, является простым для понимания, предсказуемым и обычным поведением.

Между прочим, вся перегрузка += в python очень неприятна, она открывает такие тонкие ошибки сглаживания, как это:

>>> x = [1,2,3]; y = x
>>> x += [4]
>>> print(x,y)
[1, 2, 3, 4] [1, 2, 3, 4]
>>> x = x + [5]
>>> print(x,y)
[1, 2, 3, 4, 5] [1, 2, 3, 4]

Я думаю, что эта дискуссия действительно подходит к значительному завершению (!!).

Следующий шаг звучит так, как будто это будет хороший проект, который может сделать любой бесстрашный кодер: создать хорошо протестированную, надежную функцию конкатенации последовательностей. Ей даже не нужно было бы писать это по буквам ++ , но это также несложно добавить в таблицу операторов парсера . Так что, если вы чувствуете себя здесь уверенно, действуйте. (Применяются обычные предостережения, просто потому, что вы кодируете, это не означает, что он будет объединен и т.д.).

Жаль, что у нас не могло быть «_» в качестве оператора конкатенации строк. Поскольку это то, что он делает в любом случае, когда используется в именах переменных ...

Если бы это был оператор конкатенации строк, вы не могли бы использовать его в именах переменных ...

Тогда программа

Просто вопрос ... и, пожалуйста, никого не пугайте! Могут ли комбинации, такие как $+ $/ $* , использоваться в качестве оператора? Будет ли у них проблема, возникшая для ++ (т.е. a + +b )? (кроме того, на первый взгляд это немного запутанно для программистов на C / C ++ / C # / Java ...)

Мне нравится $ как (часть) оператора цепочки строк, он имеет хорошее сходство с использованием $ в качестве оператора интерполяции строки, а $ выглядит как S для строки.

Если я смогу выяснить (возможно, с некоторой помощью :-)), как разрешить парсеру схемы разрешать $ + $ * $ / и т.д. в качестве токенов, я сделаю вилку, чтобы люди попробовали это, посмотрите, как они нравится это...

На самом деле это очень просто. Я думаю, все, что вам нужно, это добавить его в список операторов с надлежащим уровнем приоритета: src / parser. scm: 16 . Вам даже не нужно перестраивать всю Джулию, чтобы проверить это - просто make -C src и это займет 5 секунд. Я думаю, что $$ тоже открыт.

если * трудно запомнить, я не понимаю, как $+ проще. Кроме того, я думаю, что лучше просто научить, что IOBuffer является абстракцией построителя строк в Julia, и покончить с этим, а не иметь изменяемую строку (с методами append! и insert! ) и объект IOBuffer (с методами print и write ) и сообщающий пользователю, чтобы он попытался выбрать правильный.

Использование отдельного неарифметического оператора для конкатенации последовательностей дает некоторое концептуальное преимущество. IOBuffer - правильный инструмент для строк, но на самом деле он не распространяется на произвольные типы контейнеров.

Я думаю, что $$ было бы намного легче запомнить, чем, например, $+ .

Просто мысли:

  1. Если есть проблема с реализацией ++ , почему бы вместо этого не ** ? [1]
  2. Пожалуйста, никаких комбинаций $ ! ИМХО это слишком загадочно.
  3. ** основывается на фактическом * и предлагаемом ++ .

Я думаю, что "a" ** "b" чтобы получить "ab" (или объединить другие последовательности), не кажется плохим.

  • [1]: Python и Ruby используют ** для возведения в степень вместо ˆ (есть даже синтаксическое предупреждение):

julia julia> ** ERROR: syntax: use "^" instead of "**"

Это может быть просто задокументировано в отличие от других языков в FAQ.

@vtjnash Проблема с * заключается в том, что он сбивает с толку почти всех, кто более естественно ассоциирует умножение с умножением чего-либо, что будет повторяться для строки.
В любом случае $ часто ассоциируется со строками и + для конкатенации (+ означает, что вы что-то _добавляете_ к строке, т.е. конкатенацию) ... поэтому я подумал, что $ + будет хорошим выбором ...

1) Его нельзя спутать ни с какими математическими операторами (по крайней мере, на основных языках, с которыми я знаком),
в отличие от ++ , ** , + , * , <> , || , & , ~ , которые используются в других языках.
2) Он не перегружает что-то еще и поэтому может использоваться как общий оператор конкатенации,
т.е. vcat для векторов ...
3) У него нет проблем с синтаксическим анализом (по крайней мере, о которых я знаю до сих пор), которые есть у ++ , которые
Я думаю, что поднял @StefanKarpinski .
4) Напоминает как "строку" $, так и сложение +.

Для людей, выполняющих манипуляции со строками, королевская боль - пытаться кодировать все, используя IOBuffers ... код не выглядит интуитивно понятным, не имеет строковых операций, которые вам нужны, может иметь больше накладных расходов, чем когда вы просто хотите выполнить некоторые операции, например:
`mystr [5:10] =" fish "# т.е. заменить подстроку между символами 5 и 10 на" fish "` `

@toivoh По крайней мере, для людей, пришедших с одного из языков, используемых для манипуляций со строками / базами данных, $$ запутает людей, он указывает на явный вызов функции ... и в нем нет ничего, что указывает на конкатенацию, в отличие от для повторения, разделения или разрезания строки на символ или подстроку ... Например, $* может означать повторение, "foo" $* 3 получит "foofoofoo" и "foo,bar,baz" $/ "," (или даже ',' ) вернет кортеж ("foo","bar","baz") , что, на мой взгляд, было бы неплохо ;-)

@ Ismael-VC ** очень часто используется для возведения в степень ... Вся моя причина, по которой я поднимаю этот беспорядок, состоит в том, чтобы избежать путаницы, насколько это возможно, как для людей, пришедших не из Джулии, так и для Джулианцев, где перегрузка оператор * с чем-то принципиально совершенно другим может вызвать головную боль.
Если вы видите в коде ** b, вы действительно думаете в первую очередь о конкатенации строк?
Во-первых, вы, вероятно, подумаете, что это возведение в степень, если вы пришли из многих других языков ...
Во-вторых, ничто не указывает даже на то, что вы выполняете строковую операцию.

+ на строках может выдавать ошибку, ERROR: syntax: use "$+" instead of "+"
* в строках в какой-то момент может быть устаревшим (без спешки, если у нас есть новый согласованный синтаксис, к которому люди переходят), и он мог бы сказать: ERROR: syntax: use "$+" instead of "*" ,
то же самое для "^" ... ERROR: syntax: use "$*" instead of "^" .

@mbauman Отличная помощь !!! Всего лишь пара простых дополнений к уже имеющимся таблицам, я сделал make -C src, да, очень быстро (если бы я знал об этом раньше ;-)), а затем я сделал $+ = string (что, как я понимаю, может быть слишком упрощенным), но эй, это сработало! Ой, вся хвала красоте и силе Юлии! ;-)
(и слава тому, кто написал парсер ... Раньше мне платили как UTA, чтобы помочь студентам с их кодом схемы в 6.001 ... даже после того, как не использовал схему в течение 30 лет, этот код выглядел довольно понятным)

Единственное, что я сейчас пытаюсь понять, это как заставить $ + действовать как vcat на векторах ...
Помоги пожалуйста?

поскольку $ - это символ интерполяции, $+ уже означает интерполяцию + а $$ уже используется как оператор для двойной интерполяции (например, из внешнего объем).

и добавление метода для этой операции не меняет того факта, что операция O(n*m) и поэтому нежелательно обучать

Меня беспокоит только то, что это злоупотребление значением функции * generic.

Я не считаю это злоупотреблением значением * . С другой стороны, было бы интересно (если забавно), если бы сдвиг Цезаря можно было записать как (((uppercase(string) - 'A') + shift) % 26) + 'A' . Поскольку + является поэлементным, это разумно (тогда как .* было бы оператором поэлементного умножения строк). Я думаю, что общий вопрос, который это создает, заключается в том, должен ли случай string * non-string продвигать не-строку в строку, или он допустим только для использования при объединении строк.

@vtjnash Это неверно. $ ТОЛЬКО $$ . Вне строкового литерала $ обычно означает побитовый XOR в Julia, а
$$ , $+ , $* , $/ вообще ничего не значат. В настоящее время они вообще не анализируются. Интересно, что кто-то уже добавил поддержку парсинга .. , но на данный момент она ни для чего не используется.

@ScottPJones Это немного сложнее: http://docs.julialang.org/en/latest/manual/metaprogramming/#interpolation

.. необходимо анализировать как оператор, поскольку ... является допустимым оператором и, как особенность синтаксического анализатора, все префиксные строки оператора также должны быть в списке операторов.

@nalimilan Черт ! Полностью ли это исключает возможность использования $ + в качестве общего оператора конкатенации? Кажется, все работает нормально, когда я изменил синтаксический анализатор, чтобы принять его, и запустил все модульные тесты ...
Спасибо за указатель ... Я только что смотрел на интерполяцию строк.

@vtjnash Хорошо, это странно ... Я видел разговоры об использовании ... для разных вещей, и подумал, что он уже поддерживается в парсере по этой причине (для пакетов, тестирующих идеи, которые использовали его)

@ScottPJones , возможно, это было непонятно, но @vtjnash объяснял, почему .. можно анализировать, но не использовать. Определить и использовать это нормально:

julia> ..(a, b) = a:b
.. (generic function with 1 method)

julia> 1..4
1:4

Я на самом деле представлял, что .. может использоваться для чего-то, может быть, интервалов или конкатенации. Это было предложено и для "минусов" (# 3160).

Если бы это было на мое усмотрение, я бы предпочел иметь только string() . Он избегает этой дискуссии, он однозначно преобразует вещи в строки (в отличие от обработки их как последовательностей) и помогает препятствовать построению строк O (n ^ 2). string(string(string(a,b),c),d) выглядит столь же неэффективно. С оператором возникает соблазн написать

a ++= b
a ++= c
a ++= d

С синтаксисом функции очевидный способ написать это - string(a,b,c,d) . Конечно, это не «решает» построение строки O (n ^ 2), но я думаю, что это помогает.

@JeffBezanson :: +1:

Кроме того, в общем, если люди настаивают на инфиксе для своей любимой функции, то у Джулии просто может не хватить операторов для всего (ограничиваясь ASCII). Большая часть приведенного выше обсуждения просто отражает это: трудно найти инфиксную операцию для конкатенации строк, потому что осталось не из многих, из чего можно было бы выбрать. Учитывая string , $ -interpolation, @sprintf и библиотеки (например, форматирование ), нужна ли инфиксная операция для concat строки?

3 мая 2015 года в 16:41 Тамас К. Папп [email protected] написал:

@JeffBezanson https://github.com/JeffBezanson : [изображение:: +1:]

Также, как правило, если люди настаивают на инфиксе для своей любимой функции,
то у Юлии просто может не хватить операторов на все (ограничение
в ASCII). Большая часть приведенного выше обсуждения просто отражает это: трудно
найти инфиксную операцию для конкатенации строк, потому что осталось не так много
Выбери из. Данная строка, $ -интерполяция, @sprintf и библиотеки (например,
Форматирование https://github.com/lindahua/Formatting.jl) - это инфиксный оператор
для строки concat что нужно?

Кто-то должен это сказать: почему бы и нет после добавления смайлов: smile_cat:
для цепочки :)

-
Ответьте на это письмо напрямую или просмотрите его на GitHub
https://github.com/JuliaLang/julia/issues/11030#issuecomment -98443533.

@JeffBezanson Вот что меня действительно

Если бы это было до меня, я бы предпочел иметь только string ()

Что бы вы почувствовали, если бы я сказал, что Джулии не должно быть. * ./ и т. Д.?
Вы действительно были бы счастливы, всегда делая что-то вроде matrix_multiply (a, b)?

Кроме того, ваш аргумент об эффективности носит скорее покровительственный характер ... вы говорите людям, что вы лучше их знаете, что имеет смысл для их программирования.
Я также не вижу, чтобы это действительно помогло ... Я считаю, что люди будут программировать плохо, независимо от того, какие инструменты вы им дадите, чтобы они работали лучше. Я вижу много O (n ^ 2) [или O (n log n) только потому, что выделение увеличивается на степень 2, но это тоже не всегда хорошо] код, в котором строки создаются с помощью push! ... (и Я пытался их исправить, но с неплохими результатами по производительности).
Если .. = или ++ = или $ + = является общим оператором конкатенации векторов, то a ++ = b также по существу то же самое, что и выполнение push! (A, b).
Вы тогда собираетесь сказать, что push! (A, b) следует удалить, потому что это может привести к коду O (n ^ 2), реальные примеры которого я уже видел в коде в Base?
Оператор также имеет смысл добавлять в изменяемую строку (или IOBuffer) ... почему вы продолжаете рассматривать его с точки зрения производительности только одного типа?

@tpapp Мне очень жаль, но этот аргумент кажется мне немного абсурдным ... учитывая, что 1) синтаксический анализатор Джулии уже определяет сотни непонятных символов Unicode, которые вы можете использовать в качестве инфиксных операторов ... посмотрите src / julia-parser .scm. 2) конкатенация строк является фундаментальной операцией для большинства языков ... использование строковой интерполяции или строковой интерполяции или @sprintf некрасиво по сравнению с простым инфиксным оператором, может не работать так же хорошо [мне нужно было бы посмотреть, какой код генерирует @sprintf ]. Это НЕ тот случай, когда люди хотят использовать инфиксный оператор для своей любимой функции, это случай, когда целый класс программистов хочет, чтобы фундаментальная операция была простой для понимания (какая перегрузка * не является) и простой в использовании ...

@elextr Учитывая сотни инфиксных операторов, которые Джулия уже разрешает в синтаксическом анализаторе, может быть, кому-то стоит просто добавить _все_ возможные символы Unicode в качестве оператора! ;-)

@kmsquire Да, я это понял, и в другом месте уже

Я считаю, что операторы Unicode выбираются из определенного подмножества на основе кодов категорий. Вы можете выбрать оператор Unicode, такой как и делать с ним все, что хотите, в своем собственном коде (и довольно легко ввести это в Julia REPL, \boxplus затем нажать вкладку - у многих редакторов есть плагины для этой же функциональности). В большинстве случаев операторы Unicode могут иметь значение, зависящее от приложения, поэтому мы не дали стандартных определений в Julia для большинства из них.

Как и многие другие аргументы синтаксиса, похоже, это сводится к тому, что нет никаких невостребованных операторов ascii, с помощью которых мы могли бы избежать двусмысленности здесь. Есть много полезных операций, которые постоянно возникают, и было бы неплохо, если бы для них был синтаксис оператора / разделителя / скобки, отличного от Unicode, но редко можно найти что-то полезное.

Может оказаться полезным составить синтаксическую таблицу одно- и многосимвольных операторов ascii, чтобы перечислить, какие неоднозначности существуют для любых невостребованных комбинаций.

Парсер Джулии уже определяет сотни непонятных символов Unicode, которые вы можете использовать в качестве инфиксных операторов.

Во второй раз, @ScottPJones , мы выбрали не просто случайные символы. Очевидно, это операторы. Коды категорий Unicode говорят, что они есть, и что ж, это просто так. Если бы мы так сильно облажались, как бы вы это сделали? Использовать эти символы как обычные идентификаторы? Запретить их полностью?

Вы все время говорите, что повторяющийся push! равен O (n ^ 2), но это не так. Нет. Нет. Не вопрос мнения.

Я использую тот факт, что синтаксис подсказывает, как все должно быть сделано. Большинство людей, в том числе и я, не утруждают себя подробным изучением рабочих характеристик всего. Мы изучаем идиомы и ориентируемся на предоставленный синтаксис и на то, что хорошо выглядит. Операторы обновления, такие как + =, предлагают что-то постепенно изменять. У julia они не мутируют. Это неэффективно для строк. Я не считаю это покровительством, я считаю это попыткой избежать ловушек производительности. Делать педаль тормоза большой - не снисходительно для конструкторов автомобилей. «Что, ты думаешь, я не могу найти педаль тормоза?»

Забавно, что вы упомянули matrix_multiply(a,b) , потому что до сих пор мы были счастливы поделиться этим самым оператором с конкатенацией строк!

Я считаю, что операторы Unicode выбираются из определенного подмножества на основе кодов категорий. Вы можете выбрать оператор Unicode, такой как ⊞, и делать с ним все, что хотите, в своем собственном коде (и довольно легко ввести это в Julia REPL, boxplus и затем нажать вкладку - многие редакторы имеют плагины для этой же функциональности).

@tkelman В моем редакторе большинство символов в julia-parser.scm выглядят как пустые :-( Это затрудняло редактирование!

Есть много полезных операций, которые постоянно возникают, и было бы неплохо, если бы для них был синтаксис оператора / разделителя / скобки, отличного от Unicode, но редко можно найти что-то полезное.

Вот что меня обеспокоило, когда мне сказали, что ~ недоступен, потому что он уже был заявлен DataFrames.jl.

Может оказаться полезным составить синтаксическую таблицу одно- и многосимвольных операторов ascii, чтобы перечислить, какие неоднозначности существуют для любых невостребованных комбинаций.

Да, я думаю, это очень хорошая идея.

@JeffBezanson Я не сказал, что они были случайными, просто они были неясными ... примерно половина из них даже не отображалась в моем редакторе ... Кто-то другой, вы?, Обвинил мою идею использования $+ , $* и $/ как "случайные знаки" после того, как я уже объяснил свои рассуждения (аналогично .+ , .* , ./ )
Вы сами говорили про O (n ^ 2):

Добавление оператора конкатенации последовательностей, которого у нас просто нет, - законная идея. Очевидно, что * не будет использоваться для добавления списков или массивов. Однако, возможно, наличие оператора вызывает слишком много циклов O (n ^ 2) x ++ = y. Технически синтаксис и производительность ортогональны, но на практике синтаксис может иметь такой эффект.

Кроме того, я хочу использовать ..= или $+= для изменяемых строк (или векторов, или IOBuffers), а не для неизменяемых строк.
Думаю, имея:

myStringBuffer ..= ".txt"

_Очень_ ясно, читаемо и полезно!

Пожалуйста, вернитесь и прочтите, что я на самом деле сказал о push! ... Я сказал, что если бы не способ работы распределителя памяти, это было бы O (n ^ 2), но из-за трюк (который может тратить память) увеличения размера на степень 2, это всего лишь O (n log n).

Вы были счастливы поделиться matrix_multiply с конкатенацией строк, но для меня это сбивает с толку и не позволяет согласованно обрабатывать строки и векторы там, где это имеет смысл.
Я видел много комментариев в Google и GitHub о том, как * для конкатенации сначала удивили людей ...

myStringBuffer .. = ".txt"
Очень понятно, читабельно и полезно!

Я согласен, и я ненавижу это делать, но, к сожалению, вы будете разочарованы: a += b сразу понижается до a = a+b , поэтому вы не можете определить += отдельно от + (то же самое для всех остальных операторов этой формы). Чтобы поддержать это, нам пришлось бы сделать исключение для ..= .

Также очень тонкий момент: производительность push! не зависит от того, как работает распределитель памяти. Это часть реализации структуры данных, чтобы явно запросить больше места и отслеживать доступный резерв. Эта производительность переносима для любого типа распределения или схемы сборки мусора, в отличие от подходов, основанных на подсчете ссылок.

@JeffBezanson

Я согласен, и я ненавижу это делать, но, к сожалению, вы будете разочарованы: a + = b немедленно понижается до a = a + b, поэтому вы не можете определить + = отдельно от + (то же самое для всех других операторов эта форма). Чтобы поддержать это, мы должны сделать исключение для .. =.

Хорошо, теперь я думаю, вы, возможно, понимаете, откуда я ... Что нужно сделать, чтобы сделать исключение для ..= ? Я заметил, что ~ обрабатывается особым образом, как макрос, который по-прежнему позволяет модулям контролировать его значение ... можно ли сделать что-то подобное? Мне не нравится идея какого-то конкретного исключения ... было бы лучше, если бы можно было использовать более общую технику.

Спасибо за эту информацию.

Что касается push! , я руководствовался тем, что мне сказали ... хорошо знать, что это контролируется только реализацией структуры данных и может быть изменено (я не хочу, чтобы строки _всегда_ удваиваются в размере, когда размер составляет много мегабайт, только потому, что я добавил один дополнительный символ (например, завершение \0 ;-))

Незначительная придирка: построение последовательности с помощью push! , которая удваивает размер буфера при каждом перераспределении, на самом деле является O(n) амортизированным временем в размере результата; каждое перераспределение с размера k на 2k оплачивается с помощью k/2 пушей без перераспределения, предшествующих этому.

@toivoh Кто-то еще сказал мне, что это сработало до O (n log n) ... обычно вам не нужно копировать данные несколько раз? То есть вы заполняете 16 байтов, затем выделяете 32 и копируете 16, заполняете 32, выделяете 64 и копируете 32 и так далее, плюс время на копирование символов в буфер в первую очередь ...

Сумма всех степеней от 2 до N включительно равна 2N-1, то есть O (N). Конечно, push! на практике может работать медленно из-за дополнительной бухгалтерии и тратит впустую память.

Что будет вовлечено в создание исключения для ..= ?

См. Https://github.com/JuliaLang/julia/issues/249 и https://github.com/JuliaLang/julia/issues/3217 и https://github.com/JuliaLang/julia/issues/7052 , последний из которых уже был связан здесь. Я не думаю, что здесь особенно вероятно изменение способа работы каких-либо операторов op= (включая еще не назначенные). Учитывая, что уже существуют пакеты для выполнения операций на месте с массивами, я думаю, что лучше всего продолжить написание пакета для операций на месте со строками таким образом, чтобы не требовать особых случаев в базе Julia.

@ScottPJones : Да, O(n) ). Допустим, мы начали с буфера с 16 байтами данных, и что нам уже пришлось сделать 16-байтовые копии. Мы перераспределяем и копируем, итого 32 копии. Когда размер буфера составляет 32 байта, мы перераспределяем и копируем снова, увеличивая в сумме до 64 копий, в следующий раз 128 и так далее. Так что да, вам нужно сделать несколько копий, но в данном случае это применимо только к такой небольшой части данных, что общая стоимость все еще будет O(n) .

Это зависит от того факта, что вы увеличиваете буфер, по крайней мере, на некоторый заданный коэффициент каждый раз, если вы увеличиваете на фиксированную величину, вы получаете O(n^2) . Поэтому, если вы не хотите выделять 2 мегабайта для строки размером 1 мегабайт, я думаю, что лучше всего заранее выделить, сколько вам нужно (или немного больше, если вы можете только переоценить).

@toivoh ОК ... Я видел здесь комментарии о том, что * = является O (n ^ 2) для строк, видел плохую производительность процедур преобразования с использованием push !, кто-то еще здесь сказал мне, что способ увеличения буфера означало, что это было O (n log n), а не O (n ^ 2), и поскольку вы, ребята, в основном числовые, ребята, я принял это за чистую монету и сам не складывал ... Я только что увидел, что эти первые 16 символов копируются 16 раз, если вы увеличиваете буфер на степень от 2 до 1M, следующие 16 символов копируются 15 раз и так далее ... поэтому, когда они сказали, что это O (n log n), он имело смысл ... извините за эту путаницу, и спасибо, что просветили меня!

push! и *= не являются связанными операциями. push! - это O(n) амортизируемое при реализации как операция% роста, конкатенация строк не O(n) потому что здесь нет свободных операций, каждая новая комбинация строк требует копирования как старой, так и новые данные в новую строку. Первая строка копируется N раз, следующая строка копируется N-1 раз, ... последняя строка копируется 1 раз - это O(N^2) .

В моем редакторе большинство символов в julia-parser.scm выглядят как пустые :-( Это затрудняло редактирование!

Я думаю, вам пора найти новый редактор или хотя бы загрузить лучший шрифт https://github.com/JuliaLang/julia/blob/master/README.windows.md#unicode -font-support
эта проблема возникла первоначально, когда было предложено добавить новые операторы, и был сделан вывод, что любой редактор, который не поддерживал Unicode в 2015 году, вероятно, был слишком неактуальным, чтобы иметь значение. теперь есть плагины julia для самых популярных редакторов, которые поддерживают завершение \pi<tab> -> π .

ОТ: Я считаю, что это должно быть push!(mutablestring, character) или append!(mutablestring, string) . поскольку push! подразумевает поэлементные изменения, тогда как append! подразумевает объединение двух одинаковых объектов. не мутирующая форма append! моему мнению, наиболее близка к vcat , так что vcat(string, string) => string предположительно будет значимой операцией.

@vtjnash Я говорил о наличии оператора добавления строки, который также работал с векторами ...
не текущий оператор *= , и я знаю все о проблеме O (n ^ 2) ... Я просто совершил ошибку, не зная, как именно происходит выделение памяти Julia для массива с помощью push !, что это было O (n ^ 2)
(представьте производительность, которую я видел, это было простое предположение)

Что касается редактора, он поддерживает Unicode, и примерно половина списка странных символов Unicode действительно обнаружилась ... Это действительно проблема со шрифтом ... но не редкость! Пока этого не произошло, я не осознавал, что в шрифте отсутствуют какие-либо символы ... В нем есть японские, китайские, корейские и большинство из этих математических ...

ОТ: я считаю, что это должно быть push! (Изменяемая строка, символ) или добавление! (Изменяемая строка, строка). с тех пор, как нажать! подразумевает поэлементные изменения, тогда как append! подразумевает объединение двух одинаковых объектов. немутантная форма append! Я считаю, что это почти vcat, поэтому vcat (string, string) => string предположительно будет значимой операцией.

Я думаю, что большинство "строковых" людей, таких как я, сочли бы, что символ на самом деле просто 1-элементная строка,
или строка - это просто массив символов ... подумайте о C, C ++, Go, Haskell ... обо всех языках, у которых даже нет отдельного типа символа (вы просто используете строки длиной 1) ...
Это различие не имеет значения с тех пор для моего программирования, и теперь оно даже не согласовано в Джулии ...

julia> string("foo",'\n')
"foo\n"
julia> "foo" * '\n'
ERROR: MethodError: `*` has no method matching *(::ASCIIString, ::Char)
Closest candidates are:
  *(::Any, ::Any, ::Any)
  *(::Any, ::Any, ::Any, ::Any...)
  *(::AbstractString...)
julia> "foo" * "\n"
"foo\n"

Вот почему я думаю, что необходим новый оператор, который работал бы последовательно во всех этих случаях ... и даже мог бы работать с буферами IOBuffers ...

MyBuff ..= myline
.... other code ...
MyBuff ..= '\n'
MyBuff ..= "Scott was here!"

Я бы также сказал, что, возможно, этот оператор, который вы действительно хотите, чтобы люди использовали только для изменяемых типов, может просто выдать ошибку, если вы попытаетесь использовать его для неизменяемого типа ...

MyString::UTF8String = "My string"
... code ...
MyString ..= "\n My bad!"
-> would get a compile time error... (or would it be a run-time error?)

Говоря о .. , следует отметить, что # 5715 все еще встречается в v0.4:

#  Version 0.4.0-dev+4629 (2015-05-04 00:27 UTC)

julia> ..(a, b) = a * b
.. (generic function with 1 method)

julia> "a".."b".."c"
ERROR: syntax: extra token ".." after end of expression

TL; DR (я пытался, сканировал и читал больше всего .. и все это на форуме julia, который я начал, и только сейчас обнаружил эту ветку).

"a * b * c, по крайней мере, не больше, чем со строкой (a, b, c)"

Я не уверен, что это означало, что a_b_c преобразуется в строку (a, b, c), то есть одно применение строковой функции (или три).

Я не понял за или против операторов + или *. Если не используется +, я не отдаю предпочтения никакому другому. Просто знай || используется в SQL или просто как функция concat (a, b) или cat (a, b). Я мог поехать без оператора.

Больше всего меня беспокоит, медлит ли Джулия. И по умолчанию. Может ли любая конкатенация не дать вам веревки и быть быстрее? А если попробовать подставить в середину веревки, то получится не веревочная?

@PallHaraldsson См. Https://github.com/JuliaLang/julia/issues/2301#issuecomment -13573303, почему мы не используем RopeStrings по умолчанию. Но дальнейшее обсуждение характеристик струн должно быть вынесено в отдельный выпуск.

Мне кажется, что строки в Julia синтаксически похожи на символьные массивы (например, строка может быть проиндексирована / разбита на подмножества так же, как и массив). Поэтому я думаю, что семантика append! может быть более подходящей, чем push! когда дело доходит до конкатенации строк.

Что касается введения нового перегруженного оператора для конкатенации, я склонен думать, что + - лучший выбор просто из-за более широкого распространения. Проблема, конечно, в том, что + уже перегружен для массивов и его семантика не имеет ничего общего с конкатенацией. Однако выбор оператора для переопределения в основном является делом личного вкуса - я считаю, что более важным является последовательность в семантике оператора; какой бы оператор мы ни подумали для этой задачи, он должен уметь объединять все одномерные (или многомерные) массивы с минимальным неожиданным поведением.

Возможно, нам следует просто отказаться от операторов ^ и * и оставить конкатенацию явно названным функциям, чтобы избежать путаницы.

-100 для удаления * для конкатенации строк. Это очень удобно на практике и делает код очень читабельным. Аргумент, что это может быть неэффективным, на мой взгляд, неверен. В этом случае мы также должны удалить добавление трех векторов a+b+c что также неэффективно из-за созданных временных файлов.

@tknopp Я не согласен с тем, что * делает код очень удобочитаемым, поскольку это сюрприз для всех, кто только начинает изучать этот язык, и заставляет людей больше думать о повторении, а не о конкатенации, а также о том, что вещи, к которым он применяется, - это строки, векторы или скалярные числа ...
Я думаю, что наиболее популярным предложением является замена * на ++ стиле Haskell.

Этот вопрос должен определяться практическим опытом, а не с академической точки зрения. В последние годы никогда не было много дискуссий о том, что * - это неправильно. Почему вдруг возникла проблема?

В принципе, меня бы устроило + но я не вижу достаточных оснований для того, чтобы + было бы лучше.

Кстати, использование * довольно распространено в теоретической информатике (формальные грамматики). Здесь * с пустой строкой "" образуют моноид.

Я начинаю думать, что мы должны просто попросить власть предержащих принять окончательное решение, а затем перестать беспокоиться об этой теме.

@tknopp Как уже много раз говорилось в этой теме, + не будет хорошим выбором по некоторым из тех же причин, по которым * не был хорошим выбором. Также было много дискуссий о том, что * сбивает с толку и т. Д. ++ будет работать, потому что это только унарный оператор в других языках, кроме Haskell, где это оператор конкатенации.

@johnmyleswhite : да, согласен. Но я думал, что они это сделали несколько лет назад. В какой-то момент приходится придерживаться выбора.

Что ж, возможно, власть имущие решат закрыть этот вопрос.

O (n) для a * b * c * d ... конкатенация не подходит.

В этом случае мы также должны удалить добавление трех векторов a + b + c, что также неэффективно из-за созданных временных файлов.

Возможно ли понизить повторяющиеся инфиксные операторы до +(a, b, c) / *("a", "b", "c") ? Когда это имеет смысл / определяется ...

_ (ИМО, на котором корабль плыл * для конкатенации строк, любой аргумент для взлома кода каждого должен быть ... сильным.) _

Возможно ли понизить повторяющиеся инфиксные операторы до + (a, b, c) / * («a», «b», «c»)? Когда это имеет смысл / определяется ...

Это не?

julia> Meta.show_sexpr(:("a" * "b" * "c"))
(:call, :*, "a", "b", "c")

@hayd Я не думаю, что корабль отплыл, не для того, чтобы сделать что-то вроде ++ качестве общего оператора конкатенации (не только для строк) или даже для того, чтобы, возможно, отказаться от * в качестве оператора конкатенации строк , если люди отстают, используя вместо этого ++ .

Независимо от того, использует ли корабль новые операторы конкатенации или нет, * и + являются только бинарными операторами?

Я могу быть не прав:

Юлия> а = 10

Юлия> дамп (:( а_а_а))

Expr
head: вызов символа
args: Array (Any, (4,))
1: символ *
2: Символ а
3: Символ а
4: Символ а
тип: любой

julia> println (а, а, а)
101010

Julia> println (a_a_a) # не то же самое, как если бы a оказалась строкой "10"
1000

Так же, как println и многие функции, включая b = string (a, a, a),
объединяет, я не уверен, что нам нужно больше операторов для этого? Разве это не может быть
рекомендуемый способ?

Как показано выше, * или что-то еще может быть оценено один раз как операция конкатенации строк, а не
конечно. Это то, что уже сделано со строкой, и в моей идее нового изменяемого
strings было бы полезно не выполнять операцию трижды (это сэкономит место).

[Существует вероятность того, что для объединения вам не нужно искать дальше
что Informix 4GL :)]

@ScottPJones : «++ общий оператор конкатенации (не только для строк)», что вы имеете в виду? Если 1 ++ 1 должно быть «11», а не 2, это плохая идея?

@PallHaraldsson Как я уже сказал, мне нужен общий оператор конкатенации для строк и векторов (например, vcat ). Я никогда не говорил, что хочу, чтобы этот оператор использовался для скаляров (думаю, это не лучшая идея,
это просто делает вещи более запутанными).

Прямо сейчас существует ряд проблем с непротиворечивостью, таких как:

julia> b"a" * b"b"
ERROR: MethodError: `*` has no method matching *(::Array{UInt8,1}, ::Array{UInt8,1})
Closest candidates are:
  *(::Any, ::Any, ::Any)
  *(::Any, ::Any, ::Any, ::Any...)
  *{T<:Union(Float64,Complex{Float32},Complex{Float64},Float32),S}(::Union(SubArray{T<:Union(Float64,Complex{Float32},Complex{Float64},Float32),2,A<:DenseArray{T,N},I<:Tuple{Vararg{Union(Range{Int64},Int64,Colon)}},LD},DenseArray{T<:Union(Float64,Complex{Float32},Complex{Float64},Float32),2}), ::Union(SubArray{S,1,A<:DenseArray{T,N},I<:Tuple{Vararg{Union(Range{Int64},Int64,Colon)}},LD},DenseArray{S,1}))
  ...

julia> vcat(b"a", b"b")
2-element Array{UInt8,1}:
 0x61
 0x62

Общий оператор конкатенации, как я предлагал, ++ или .. или что-то еще, устранит такое противоречивое поведение.

@scottjones : "Я никогда не говорил, что хочу, чтобы этот оператор использовался для
скаляры "- хорошая (или плохая) идея исключить числа, которые
уже обработано:

julia> print ("Палл", 1.0, 1)
Páll1.01
julia> строка ("Палл", 1.0, 1)
"Páll1.01"

@PallHaraldsson Проблема в том, что и print и string делают гораздо больше, чем просто конкатенацию, они "привязывают" свои аргументы ... Я не уверен, что это должно происходить _неявно_ с общий оператор конкатенации. Этого не происходит с * настоящее время при использовании в качестве оператора конкатенации строк.
Кстати, вам нужно научиться цитировать здесь вещи с помощью Markdown ... люди здесь любезно показали мне, как использовать тройные обратные кавычки, за которыми следует julia, вокруг фрагментов кода Julia и помещать пустую строку после цитирования кого-то с > и ваш комментарий.
т.е. что-то вроде:

@scottjones :

Я никогда не говорил, что хочу, чтобы этот оператор использовался для скаляров

это хорошая (или плохая) идея исключить числа, которые уже обработаны:

julia> print("Páll", 1.0, 1)
Páll1.01
julia> string("Páll", 1.0, 1)
"Páll1.01"

@ScottPJones , к сожалению, цитирование не работает при ответе
электронное письмо, даже если вы редактируете постфактум (проверяйте это здесь).

print("Hi GitHub!  Is this quoted")

@PallHaraldsson , будь осторожен при написании чьего-либо имени. Вы
на самом деле отправил сообщение другому Скотту Джонсу, который, вероятно, был
Я не понимаю, что получил от вас уведомление о Юлии.

В любом случае, используя интерфейс GitHub, а не отвечая по электронной почте,
действительно помогает с обоими этими вещами.

В сб, 13 июня 2015 г., в 5:24, Скотт П. Джонс [email protected]
написал:

@PallHaraldsson https://github.com/PallHaraldsson Проблема есть
что и print, и string делают гораздо больше, чем просто конкатенацию, они
"преобразовать" их аргументы ... Я не уверен, что это должно происходить
_неявно_ с помощью общего оператора конкатенации. Не бывает
с * в настоящее время также при использовании в качестве оператора конкатенации строк.
Кстати, вам нужно научиться цитировать здесь с помощью Markdown ... люди
здесь любезно показал мне, как использовать тройные обратные кавычки, за которыми следует Юлия
вокруг фрагментов кода Джулии и ставьте пустую строку после цитирования
с> и вашим комментарием.
т.е. что-то вроде:

@scottjones https://github.com/scottjones :

Я никогда не говорил, что хочу, чтобы этот оператор использовался для скаляров

это хорошая (или плохая) идея исключить числа - которые уже
обработано:

julia> print ("Палл", 1.0, 1)
Páll1.01
julia> строка ("Páll", 1.0, 1) "Páll1.01"

-
Ответьте на это письмо напрямую или просмотрите его на GitHub
https://github.com/JuliaLang/julia/issues/11030#issuecomment -111706133.

Ух ... Я не знал, что @PallHaraldsson отвечал по электронной почте, и что в этом письме не было этой проблемы (я использую приложение CodeHub, когда меня нет на ноутбуке ... у него свои проблемы, но не то).
Да, это совсем другой Скотт Джонс ... даже не Скотт А. Джонс, который был аспирантом Массачусетского технологического института, когда я был студентом, а потом тоже жил в Арлингтоне!

LOL, да, это сбивало с толку! Я встречался с «собой» несколько раз за эти годы, так что это не первый раз, когда случается такая путаница. :)

Привет,

-Скотт

13 июня 2015 г. в 11:37 Скотт П. Джонс < [email protected] [email protected] > написал:

Ух ... Я не знал, что @PallHarald ssonhttps: //github.com/PallHaraldsson отвечал по электронной почте, и что в этом письме не было этой проблемы (я использую приложение CodeHub, когда я не на своем ноутбуке ... у него есть свои проблемы, но не это).
Да, это совсем другой Скотт Джонс ... даже не Скотт А. Джонс, который был аспирантом Массачусетского технологического института, когда я был студентом, а потом тоже жил в Арлингтоне!

-
Ответьте на это письмо напрямую или просмотрите его на Gi tHubhttps: //github.com/JuliaLang/julia/issues/11030#issuecomment -111727642.

Как бы то ни было, мне действительно нравится * качестве конкатенации строк. Во-первых, это соответствует обозначениям, используемым в _Computability, Complexity, and Languages_ Дэвиса и др. Это также дает вам бесплатную конкатенацию сопоставлений (не то, чтобы я когда-либо видел, чтобы это использовалось, это просто здорово). Я все время использую * , и я видел, что он используется во многих других местах, поэтому я думаю, что масштаб оттока кода для этого устаревания будет огромным, с (по крайней мере, IMHO) мало пользы.

Я думаю, мы должны просто оставить * для строк, но, возможно, добавить ++ позже как общий оператор конкатенации (который будет поддерживать строки, а также другие вещи).

Мы можем добавить ++ в качестве общего оператора конкатенации последовательностей в будущем, но похоже, что избавления от * и ^ для строк не произойдет. Я скажу, что меня больше не беспокоит "каламбур" на * , и я даже не думаю, что это больше каламбур - в абстрактной алгебре, умножении (представленном как * или сопоставление) часто используется как некоммутативная групповая операция над вещами, не являющимися числами. Основные проблемы здесь были связаны с тем, что ранее Char <: Number но операция * для Char была несовместима с * для Number . Теперь, когда Char не является подтипом Nubmer , это больше не проблема.

Я бы оставил * для конкатенации строк по первоначальной причине.

Вот что Википедия говорит о регулярных выражениях как алгебраических операциях:

Учитывая регулярные выражения R и S, для создания регулярных выражений над ними определены следующие операции:
(конкатенация) RS обозначает набор строк, которые могут быть получены путем конкатенации строки в R и строки в S. Например, {"ab", "c"} {"d", "ef"} = {"abd "," abef "," cd "," cef "}.
(чередование) R | S обозначает объединение множеств, описываемых R и S. Например, если R описывает {"ab", "c"}, а S описывает {"ab", "d", "ef"}, выражение R | S описывает {"ab", "c", "d", "ef"}.
(Звезда Клини) R * обозначает наименьшее надмножество множества, описываемого R, которое содержит ε и закрывается при конкатенации строк. Это набор всех строк, которые могут быть созданы путем объединения любого конечного числа (включая ноль) строк из набора, описанного R. Например, {"0", "1"} * - это набор всех конечных двоичных строк ( включая пустую строку), а {"ab", "c"} * = {ε, "ab", "c", "abab", "abc", "cab", "cc", "ababab", " abcab ",…}.

В линейной алгебре есть унарный оператор, сопряженный оператор, который часто обозначается как * . В Julia, а также в Matlab сопряженный оператор задается одинарными кавычками ( ' ), поскольку * обычно используется для умножения. Поэтому я бы предложил строковые операторы в Julia быть ( *,+,' ) для конкатенации, чередования и звезды Клини соответственно.

Как отметил @stevengj , спор между + и его конкурентами связан с соглашением, а не с правильностью. И данные @stevengj, представленные выше, ясно доказали, что + как оператор конкатенации строк является наиболее широко принятым соглашением в мире программирования (C ++ / C # / Java / Python / Javascript и многие другие). А все остальные варианты, по-видимому, встречаются гораздо реже, нравится это кому-то больше или нет.

Тогда основная причина, по которой я мог подумать о сохранении * состоит в том, что отказ от него нарушит существующий код, например “abc” * “efg” . Может ли кто-нибудь объяснить, что еще + сломалось бы при использовании в качестве оператора конкатенации строк в Julia, чтобы помочь мне лучше понять предысторию? (Я понимаю, что конкатенация строк не является коммутативной операцией.)

Ничего не сломается, и если вы действительно этого хотите, вы можете определить + для этого. Однако это просто плохая математика. В алгебре + всегда является коммутативной операцией, а конкатенация строк не коммутативна. Вы можете видеть некоторую путаницу, которую это вызывает, поскольку + не приводит к естественному способу повторения строк. Вы пишете "hi" * 5 или 5 * "hi" ? Ни то, ни другое не имеет особого смысла. Сравните это с * для конкатенации, где очевидно, что вы должны написать "hi"^5 . В любом случае, хотя мы можем ввести ++ для конкатенации (включая строки), мы не собираемся использовать + для конкатенации строк, независимо от того, на скольких языках может быть выбран этот синтаксис.

Я предлагаю использовать . для конкатенации строк в соответствии с PHP. С перегружаемым getfield это было бы даже тривиально реализовать:

getfield(x::String, y::String) = string(x, y)
"a"."b"."c"

Мы могли бы использовать .. для повторения " "..5

@ StefanKarpinski
Спасибо за объяснение! Теперь я лучше понимаю предысторию.

(1) Если * используется для конкатенации строк, то ^ будет логической и естественной операцией повторения строки.
(2) Если + используется для конкатенации строк, то * будет логическим результатом повторения строки.
Что касается варианта (1), я согласен, что ^ - интуитивно понятный оператор для повторения строки. Для (2) даже * является логическим результатом, он все же может быть недостаточно интуитивным (например, «привет» * 3 == «привет»).

Вы пишете "hi" * 5 или 5 * "hi" ?

Нет, повторение строки (какой бы оператор это ни было) для меня не частая операция. Но конкатенация строк есть. Если это общий случай, кажется, есть смысл заменить оператор повторения именованной функцией (например, repeat , уже поддерживаемой в Julia).

И я понял, что создание _new_ операторов - действительно спорная / опасная вещь, хотя поддержка большего количества API обычно приветствуется :)

Изменить: нашел еще один поток, который представил / и \ для строк. И это помогает мне лучше понять, почему для конкатенации строк было выбрано * .

Была ли эта страница полезной?
0 / 5 - 0 рейтинги