Julia: мини-джулеп: если х, то у

Созданный на 16 мая 2016  ·  53Комментарии  ·  Источник: JuliaLang/julia

В различных обсуждениях было предложено разрешить такой синтаксис, как:

if x then y

Как краткий оператор «если» и как альтернатива общему:

x && y

синтаксис, который использует укорачивающий оператор && для условного выполнения y (при этом y часто содержит другие побочные эффекты и не обязательно возвращает Bool ).

Основными преимуществами этой конструкции if-then являются: более разборчивый код, меньшая зависимость от злоупотребления && и формальное включение формы оператора «если», которая не требует end ключевое слово.

На днях мне пришло в голову, что этот синтаксис также предоставит удобное средство для реализации #550, которое будет выглядеть так:

A = [if x % 2 == 0 then f(x) for x in 1:10]

Опираясь на тот факт, что if-then не требует ключевого слова end , которое нам, вероятно, все равно понадобится в той или иной форме, даже если мы пойдем с охранниками в стиле Python:

A = [f(x) for x in range(10) if x % 2 == 0]

Чтобы было ясно, синтаксис гвардии Джулии, по сути, будет переписываться из:

A = [if x % 2 == 0 then f(x) for x in 1:10]

к

A = [Filter(x->x % 2 == 0, f(x) for x in 1:10)]

Также в качестве поясняющего примечания это будет разрешать синтаксис защиты на уровне _generator_, а не только на уровне _comprehension_ (что также соответствует тому, что позволяет python).

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

Возможно, я в меньшинстве, так как другие языки используют этот подход, но я всегда находил действие, предшествующее условию, очень странным, например, println("positive") if x > 0 . Я предполагаю, что это более лаконично, чем if x > 0 println("positive") end , но, по крайней мере, для меня это происходит за счет удобочитаемости.

Я думаю об этом как о разговоре:

Джулия: "Я напечатаю строку..."
Гарольд: «Отлично!»
Джулия: "...но только при соблюдении некоторых условий."
Гарольд: "О. :("

против

Джулия: «Если какое-то условие будет выполнено, я напечатаю строку».
Гарольд: «Хорошо, круто».

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

Похоже, что синтаксис модификатора if/for в стиле Perl/Ruby будет лучше сочетаться с этим. Другими словами:

println("positive") if x > 0         # conditional execution
x^2 for x=1:100                      # generator
[ x^2 for x=1:100 ]                  # comprehension
x^2 if x % 3 == 0 for x = 1:100      # filtered generator
[ x^2 if x % 3 == 0 for x = 1:100 ]  # filtered comprehension

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

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

Да, хороший момент. Действительно, № 6823, кажется, находится в середине обсуждения и, вероятно, не должен был быть закрыт.

Возможно, я в меньшинстве, так как другие языки используют этот подход, но я всегда находил действие, предшествующее условию, очень странным, например, println("positive") if x > 0 . Я предполагаю, что это более лаконично, чем if x > 0 println("positive") end , но, по крайней мере, для меня это происходит за счет удобочитаемости.

Я думаю об этом как о разговоре:

Джулия: "Я напечатаю строку..."
Гарольд: «Отлично!»
Джулия: "...но только при соблюдении некоторых условий."
Гарольд: "О. :("

против

Джулия: «Если какое-то условие будет выполнено, я напечатаю строку».
Гарольд: «Хорошо, круто».

@ararslan : Я не согласен, и это одна из причин, по которой этой функции нет в Джулии, несмотря на предшествующий уровень техники в Ruby и Perl. Однако он намного лучше сочетается с синтаксисом модификатора for для генераторов и вкраплений, поэтому я привел его здесь.

@StefanKarpinski Да, согласен, с ними он лучше сочетается. Однако я все еще безнадежно привязан к условиям, предшествующим действиям. :smile: (Но, как я в последнее время часто говорю, мое мнение на самом деле не имеет значения, я просто какой-то парень.)

Я полагаю, если бы у вас было что-то вроде

if x % 3 == 0 then x^2 for x = 1:100

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

if x % 3 == 0 then (x^2 for x = 1:100)

т.е. если какое-то условие, то генератор. я бы не возражал

if x % 3 == 0 x^2 end for x = 1:100            # More obvious what's happening, IMO
filter(x -> x % 3 == 0, [x^2 for x = 1:100])   # Verbose, but... ¯\_(ツ)_/¯

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

x^2 for x = 1:100 where x % 3 == 0

Я думаю, что where делает более ясным, что вы фильтруете значения x , созданные for , чем это делает if .

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

Можете ли вы уточнить, что вы подразумеваете под этим?

for 1:n «генерирует» значения, if x % 3 == 0 фильтрует их, а x^2 преобразует их — генераторы уже текут справа налево, и чтобы сохранить этот поток, фильтр должен идти в середина. Если предложение if идет справа от предложения for , тогда данные «перетекают» из середины в крайнее правое, а затем в крайнее левое положение, что странно. Если предложение if находится слева, то данные «перетекают» от крайнего правого края к крайнему левому и к середине. Я знаю, что SQL помещает предложение where справа от имен таблиц, а выражения — слева, потому что это больше похоже на английский, но меня всегда раздражало чтение, и я думаю, что чтение на английском не является эвристикой, которую следует заходить слишком далеко в разработке языка программирования.

Что мне не нравится в if x then y :

  1. Он вводит новое ключевое слово then .
  2. Написать if x y end короче, чем if x then y ; x && y еще короче.
  3. Ключевое слово then широко используется в языках для совершенно противоположного синтаксиса: многострочный синтаксис if , для которого требуется ключевое слово end (или fi в bash). , фу).

О да, теперь я понимаю, что вы имеете в виду о потоке. В этом есть смысл. Спасибо за объяснение!

Было бы странно иметь возможность сделать

x^2 if x % 3 == 0 for x = 1:100

и _не_ уметь делать

println("positive") if x > 0

?

Все хорошие моменты.

Мне действительно очень нравится синтаксис @StefanKarpinski, впервые предложенный в его первом комментарии. Меня в основном интересуют условные генераторы с более общей краткой формой _if_ в качестве бонуса.

Что касается генераторов, я читал, что if (или where - у меня нет мнения по этому поводу) является частью диапазона... он создает итератор x = 1:10 if/where x % 2 == 0 , который затем объединяется с выражением слева для создания массива (или генератора).

В некотором смысле, x = 1:10 where x % 2 == 0 сам по себе является генератором для какого-то итерируемого объекта. Это может быть автономный синтаксис, нет?

Я чувствую, что фильтрация в чем-то отличается от условного оператора if a then b . Фильтрация действует в диапазоне итераций. Когда if a then b комбинируется с выражением слева от генератора, я ожидаю, что он выдаст nothing в случаях, когда a было false . Сравните, что логически получится, если я добавлю скобки:

[(x^2 if i % 2 == 1) for i = 1:10] # [nothing, 4, nothing, 16, nothing, 36, nothing, 64, nothing, 100]
[x^2 (for i = 1:10 where i % 2 == 0)] # [4, 16, 36, 64, 100]

Беря примеры @ararslan , если мы позволим

println("positive") if x > 0

тогда ИМХО следует, что

x^2 if x % 3 == 0 for x = 1:100

вероятно, должен излучать nothing, nothing, 9, nothing, nothing, 36, ...

Наконец, если бы мы приняли сокращенное условное выражение if , я бы проголосовал за условие перед утверждением по причинам, изложенным в первом сообщении @ararslan - это принцип наименьшего удивления при чтении кода. (помните, если они говорят, что код больше читается, чем пишется, то синтаксис if a then b лучше, чем a && b даже если последний короче). Это также означает, что два возможных типа if внутри генератора будут различаться — крайний левый — выражением — или крайний правый — диапазоном.

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

Кроме того, если у нас есть диапазоны if/where , должны ли мы соблюдать осторожность, чтобы убедиться, что диапазон остается декартовым для многомерных генераторов?

# Make a circular array (filled with distance to center)
r = 5
[sqrt(x^2 + y^2) for x = -5:5, y = -5:5 where x^2 + y^2 <= r^2]

Это как-то круто и как-то ужасно!

Я чувствую, что фильтрация как-то отличается от условного оператора if a then b.

Да! Я собирался оставить этот же комментарий. Фильтрация воздействует на итератор в целом и не является частью вычисляемого выражения внутри.

Я также чувствую то же, что и @andyferris , что if между выражением и итерацией, кажется, «преобразует» значение выражения, а не форму итерации, и должно производить nogthing , когда условие не выполнено (но я могу быть избалован пониманием python/haskell).

Очевидно, что x if false оценивается как nothing , если не находится в контексте выражения генератора. Было бы совершенно разумно поддерживать [x^2 if x % 3 == 0 for x=1:100] , но не x if y отдельно.

Лично я бы предпочел опустить end , если есть только одно утверждение.

if length(A) != length(B) throw(ArgumentError("..."))

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

Я бы предпочел это, чем иметь два разных синтаксиса для аналогичной формы оператора if;if x; ...; end и if x then; ... . _(Редактировать: if condition then action мне уже приглянулись.)_

Было бы совершенно разумно поддерживать [x^2, если x % 3 == 0 для x=1:100], но не x, если y сам по себе.

@StefanKarpinski Я полностью согласен с этим. Тем не мение...

Если предложение if находится слева, то данные «перетекают» от крайнего правого края к крайнему левому и к середине.

Я читаю x^2 if x % 2 == 0 for x in 1:10 как x^2 where x % 2 == 0 for each x in 1:10 , что, поскольку это понимание, имеет для меня смысл; вас больше всего интересует трансформация.
В SQL-запросах верно то же самое, не так ли?

Поэтому я не думаю, что использование "генератора" в качестве отправной точки для его чтения совершенно правильно, _для понимания_. С другой стороны, цикл for... Это имеет больше смысла.

Лично я предпочел бы опустить конец, если есть только одно утверждение.

Я предлагал это давным-давно, но оно не получило поддержки: https://github.com/JuliaLang/julia/issues/1657. На самом деле это было бы относительно неразрушающим изменением, поскольку было бы странно и редко увидеть код, подобный этому:

if cond body
end

Что вы думаете об использовании блоков do вместо then ? то есть: if x do y end

Небольшой побочный комментарий: я не вижу способа, которым if x y сам по себе (т.е. вне генератора) можно было бы правильно обработать в редакторе без полноценного синтаксического анализатора julia, поскольку вам нужно быть в состоянии определить, сколько жетонов следует за if . Я думаю о vim, но полагаю, что и другие редакторы могут оказаться в такой же ситуации. То же самое можно сказать и о y if x , но я не уверен (полное раскрытие: я также очень не люблю y if x сам по себе; я не против if x y в принципе, но думаю, это может быть немного сложно анализировать и для людей, а не только для редакторов).

@diegozea Думаю , та же проблема. Я все же предпочел бы if x y .

@carlobaldassi Есть некоторые вещи, которые вы могли бы сделать, чтобы людям было легче анализировать.

Вы можете заставить этот одиночный оператор if не иметь новой строки между условием и выражением.
Однако я не уверен, что хотел бы, чтобы меня заставляли делать это для длинных выражений.

В качестве альтернативы вы можете принудительно поставить новую строку после выражения, если после условия была новая строка; поэтому следующее не будет компилироваться, но, конечно, выдаст четкое сообщение об ошибке:

if length(A) != length(B)
    throw(ArgumentError("lengths must match")
if some_condition(A, B)
   N *= 2

Но это будет:

if length(A) != length(B) throw(ArgumentError("lengths must match")
if some_condition(A, B) N *= 2

и это будет:

if length(A) != length(B)
    throw(ArgumentError("lengths must match")

if some_condition(A, B)
   N *= 2

Это также убережет вас от подобных ошибок:

if is_present(x)
    y = 2 * x[]

    return y * 2

Я думаю, что самый большой аргумент в пользу if x then y , который до сих пор выигрывает у любого другого синтаксиса, — это удобочитаемость . То, что if x y end , if x y или x && y короче, не имеет значения в моей книге (помимо того факта, что мы говорим о тривиальной разнице в 1-5 символов), потому что ни один из этих почти так же ясны, как if x then y . Это также позволяет избежать проблем с разбором редактора или возможного нарушения прошлого кода. Это просто хороший, чистый, короткий синтаксис для коротких операторов if.

Однако я признаю возможную путаницу при использовании if-then в случае с генератором; учитывая это, я согласен, что

x^2 if x % 3 == 0 for x = 1:100      # filtered generator
[ x^2 if x % 3 == 0 for x = 1:100 ]  # filtered comprehension

является самым ясным, признавая, что структура выражения

generated_value_expr  value_generator_expr  =>  generator_expression

[generator_filter_expr]  for_generator_expr  => value_generator_expr

т.е. generator_filter_expr применяется непосредственно к значениям, сгенерированным из for_generator_expr , перед передачей нефильтрованных значений в generated_value_expr .

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

println("positive") if x > 0 

TL;DR: у нас должно быть x^2 if x % 3 == 0 for x = 1:100 для отфильтрованных генераторов, но та же синтаксическая логика не применяется к println("hey") if x > 0 , следовательно, мы все равно должны рассматривать if x then y для краткой формы. если-синтаксис. Хотя очевидно, что эти две идеи теперь совершенно не связаны.

@ H-225 H-225 Мне это кажется странным и, в конечном счете, не по-юлиански, особенно с действием на новой строке без end .

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

Определенно :-1: за if x y с меня. Я бы предпочел if x then y этому, так как моему маленькому мозгу легче анализировать. :stuck_out_tongue_winking_eye:

Есть ли причина не использовать троичный оператор вопросительного знака и для оператора if? Вы уже можете имитировать оператор if, выполнив

condition ? if_condition_true_eval_expr : nothing

почему бы просто не сделать так, чтобы, если вы не включаете двоеточие, это был оператор if, тогда вы бы просто

condition ? if_condition_true_eval_expr

таким образом, вам не нужно вводить новые ключевые слова, будет ли это работать?

@esproff Как ни странно, я собирался предложить обратное: расширить идею «если-то» в этом джулепе до одной строки выражения «если-то-иначе».

if cond then a else b

где предложение else является необязательным. Он может даже снизиться до cond ? b : c . Для меня это все о том, чтобы уйти от тройки в стиле C и перейти к более удобочитаемому коду. (Я определенно использовал condition ? a : nothing раньше - это похоже на хак (потому что это было так, nothing был важен по какой-то неясной причине), и это сбивает с толку других людей при чтении).

Но, конечно, почему мы не можем иметь все эти идеи одновременно?

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

if condition; eval_expr; end

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

if condition; eval_expr; end

Верно!

Как бы то ни было, мне нравится обозначение x && y, и я не считаю это злоупотреблением.

Я лично предпочитаю решение на основе оператора, которое не возвращает false , если первое утверждение ложно. Меня бы устраивало почти все, хотя мне нравится a ?: b как версия тернарного оператора с двумя аргументами.

Идея ? довольно подробно обсуждалась в #6823, возможно, стоит перечитать это обсуждение.

Я попал сюда из этого обсуждения, но решил, что это лучшее место для комментариев. Я думаю, что if a then b и использование только ? без : будут несколько запутанными, но не будут жаловаться, пока они обеспечивают одинаковую функциональность.

Я согласен с @EricForgy. Может быть, я просто привык к ним на данный момент, но для меня использование && и || таким образом кажется Джулии идиоматичным, особенно для проверки ошибок (например, x || throw(y) ). Они совсем не кажутся двусмысленными или нечитаемыми. Кроме того, я действительно не понимаю, почему имеет значение, что x && y возвращает false , если x является ложным, потому что его, вероятно, все равно не следует использовать в конце функции. , где это повлияет на возвращаемое значение функции.

Тернарии в стиле C довольно распространены; Я бы сказал, что не только математики ценят этот синтаксис. Единственный язык, который я могу придумать навскидку, который имеет троичные коды, но не поддерживает стиль C, — это Python, и FWIW я презираю троичные коды Python. condition ? action1 : action2 является одновременно компактным и удобочитаемым, если вы используете пробелы и соблюдаете длину строки. Для более длительных условий и действий следует использовать

if condition
    somelongaction1
else
    somelongaction2
end

во всяком случае для удобства чтения.

Что касается then , сути этого обсуждения, FWIW, я бы, вероятно, не использовал его, даже если бы он был реализован, потому что, опять же, && и || кажутся мне идиоматическими. Хотя я бы в мгновение ока взял then за if x y , x ? y или x ? y : nothing .

Лично я предпочитаю y if x . Может показаться, что это неправильно, но есть приоритет за пределами Ruby и Perl: в математическом синтаксисе case все обстоит именно так.

image

Я не _люблю_ использовать для этого && или || , так как я никогда не помню, что x && y = z не анализирует так, как я ожидаю. Я думаю, что у него более высокая когнитивная нагрузка, чем у y if x ; это тоже стоит if x y .

ИМО, x ? y _пахнет_ как синтаксическая ошибка, независимо от того, действительно ли это действительно так.

x ?? y возможно? x ?: y — это расширение GNU C, означающее x ? x : y , поэтому ?? и ?: могут быть версиями && и || с низким приоритетом.

Мой порядок предпочтения: y if x == x ?? y < if x then y < x && y < x ? y < if x y .

ПОМОЩЬ. Я предпочитаю краткость и четкое разделение кода с помощью ? , && и || , хотя синтаксис cond ? expr может быть более понятным, чем && .

Мне нравится часто выполнять поток типа goodcondition || return , что непросто с операторами if. Я не хотел бы потерять это (или быть запуганным, чтобы не использовать его)

Для тройки без : было бы неплохо разрешить краткие блоки if / elseif без условия else :

x==5 ? f1() :
x==6 ? f2()

и можно было бы представить, как расширить это на операторы типа switch:

match x:
    5 ? f1() :
    6 ? f2()

С точки зрения читабельности, это зависит. Для многих коротких условий/действий намного читабельнее (с чистым интервалом!!) иметь возможность выстроить условия/действия в последовательных строках с четкими разделителями.

Для генераторов я бы предпочел where или when перепрофилированию if , так как это фильтр, а не условие:

x = [i^2 for i in 1:10 when i%2 == 0]

Думаю, более понятно, что это означает x = [i^2 for i in filter(..., 1:10)] .

Замечу, что после обсуждения этого я больше не стал бы возражать против if condition then action - оно мне уже приросло.
Джулия, как правило, склоняется к более «многословной» стороне, с function и end и т. д., поэтому я думаю, что это подойдет. Также немного раздражает необходимость добавлять скобки вокруг выражения, если вы переходите туда и обратно между синтаксисом condition && action .

Что касается синтаксиса Perl/Ruby «действие при условии»: мне очень нравится этот синтаксис, и хотя я согласен с тем, что он может снизить читаемость при неправильном использовании, я также считаю, что иногда он _повышает_ читаемость.

Например:

throw(DomainError()) if some_condition || some_other_condition && so_on

После прочтения фразы «сбросить ошибку домена, если» вы уже знаете, что последующее будет проверкой работоспособности ввода. Затем вы можете перейти к следующей строке, если детали условного предложения для вас не важны.

Предыдущее предложение является примером того, как эта конструкция часто встречается в естественном языке. Действие «перейти к следующей строке» стоит первым, а менее важное «если вам не интересно» — в придаточном предложении. Опять же, читатель может примерно угадать, что последует за словом «если», даже не дочитав предложение до конца.

(Я также приведу самореферентный пример предложения, если смогу его придумать.)

Как старый специалист по Perl, я симпатизирую этому синтаксису, но я думаю, что это будет трудно продать тем, кто не имеет опыта работы с Perl. Одним из аргументов в пользу является то, что он соответствует синтаксису фильтра в понимании. Аргумент против заключается в том, что странно иметь конструкцию, в которой порядок вычислений не слева направо. Конечно, у осмыслений именно так, так что 🤷‍♂️

Тогда для меня возникает связанный с этим вопрос: обобщаем ли мы ветвление или фильтрацию? Это обобщение семантики (и синтаксиса) ветвления if , поэтому, возможно, было бы неудачно заимствовать для этой цели синтаксис из генераторов/повторений, где этот синтаксис уже указывает на фильтрацию.

(Между прочим, мне бы хотелось какой-нибудь хороший синтаксис для фильтрации, например, наш хороший синтаксис . . Чтобы проиллюстрировать мою мысль выше, возможно, map - filter может выглядеть как f.(a) if g.(a)

f(x) for x in a # lazy map
f(x) for x in a if g(x) # lazy map - filter
x for x in a if g(x) # lazy filter where `f` is `identity`

f.(a) # map / broadcast
f.(a) if g.(a) # like a map/broadcast - filter operation
a if g.(a) # like the above where `f` is implicitly `identity`
[1,2,3] if [true, false, true] == [1, 3] # or something... here we simply make `if` an infix operator for filtering

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

Наконец, я согласен с наблюдениями @tbreloff выше... двоичный код ? является наиболее компактным синтаксисом (и весь смысл этой ветки состоит в том, чтобы сделать компактный синтаксис), и я всегда находил if несколько неожиданный выбор для фильтрации генератора.

@StefanKarpinski написал:

Похоже, что синтаксис модификатора if/for в стиле Perl/Ruby будет лучше сочетаться с этим. Другими словами:
julia println("positive") if x > 0 # conditional execution x^2 for x=1:100 # generator [ x^2 for x=1:100 ] # comprehension x^2 if x % 3 == 0 for x = 1:100 # filtered generator [ x^2 if x % 3 == 0 for x = 1:100 ] # filtered comprehension
У него также есть преимущество в том, что он имеет прецедент в других языках, чего, похоже, нет в синтаксисе if-then без конца.

Да и по грамматике было бы лучше.

Я думаю, что [x^2 if x % 3 == 0 for x = 1:100] должно быть:

[(x^2 if x % 3 == 0) for x = 1:100]
 ```
Then `for` stay's in infix position which is currently an error. Of course we can change its meaning because of leading `[` but it would not work as generator:
```julia
x^2 if x % 3 == 0 for x = 1:100

Я думаю, что [x^2 if x % 3 == 0 for x = 1:100] должно быть:

Это не будет генератор с фильтром. 2 if x возвращает 2 , когда x истинно, но также должно что-то возвращать, когда x ложно; обычно это будет nothing . Так что это даст массив чисел и ничего. Отчасти поэтому if должно стоять после for в синтаксисе генератора с фильтрацией.

Да, ты прав. Может быть, это должно быть написано так:

[for x = 1:100 x^2 if x % 3 == 0]

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

Просто думаю...

[ for x = 1:100 if x % 3 == 0 push x^2]
for x = 1:100 if x % 3 == 0 push x^2  # other keyword could be used, e.g. yield

Это больше похоже на естественную конструкцию

for x=1:100 
    if x%3==0 
          push!(somearray, x^2)
    end
end

Я только что снова увидел этот джулеп, когда смотрел на что-то другое.

Я все еще хочу что-то вроде однострочной формы if a then b ; Я нахожу юлианскую замену a && b довольно нечитаемой даже после ее использования в течение нескольких лет: просто невозможно прочитать ее непосредственно как английское предложение.

Я также чувствую, что необходимость объяснять идиому a && b новичкам немного смущает, когда у нас может быть альтернативный синтаксис, который очевиден и лишь немного длиннее.

просто невозможно прочитать это прямо как английское предложение

a && b читается как «а и б», как в «если а, то также сделать б»
a || b читается как «a или b», как в «a должно быть истинным, иначе сделайте b»

Я знаю, что он делает, и иногда использую его для краткости. Но как бы я ни старался (как уже упоминалось, уже несколько лет), я не могу рассматривать «а и б» как предложение. Каждый раз это просто легкий когнитивный диссонанс.

Напротив, я всегда находил «a или b» довольно читаемым.

Забавно, но сегодня на работе два раза поднимались разные аспекты этого.

Утром у нас был PR Джулии, в котором использовалось && вместо if ... end , и я указал, что как читатель кода (рецензент по связям с общественностью) это требует дополнительных усилий (и его легко пропустить). ) ветвей, которые могут выполняться или не выполняться. Пример имел форму a() && b!() , где b! чрезвычайно мутирует. (В этом случае b!() перемещал или удалял файлы в файловой системе, что сразу казалось опасным, но мой мозг не мог понять, что это было проблематично только тогда, когда !a() и что этот случай на самом деле правильно предохранялся).

Днем другой инженер-программист (который не знает Юлию) заметил, что, говоря по-английски с друзьями, он иногда отвечал на вопрос формы «Это a или b " с ответом "да". Поймут только его друзья-программисты — все остальные не поймут вообще . Просто нормальные люди так не думают. 🙂 Это в некоторой степени относится к моему следующему пункту (РЕДАКТИРОВАТЬ: и я должен был сказать, относится к ответу Стефана выше, что для многих людей, я не думаю, что это придет им в голову).

Моя позиция по этому вопросу с самого начала заключалась в том, что использование && (или || ) является коротким синтаксисом для ветвления, который может быть прочитан только людьми с сильным опытом PL, и даже тогда добавляет немного когнитивная/визуальная нагрузка (просто чтобы отличить & от && ). Я чувствую, что при работе в междисциплинарных командах (смесь ученых и инженеров-программистов) это активно сбивает с толку половину команды. Даже будучи инженером-программистом, я чувствую странное несоответствие между логическим &(::Bool, ::Bool) --> Bool и ветвящимся &&(::Bool, ::Any) --> Any (да, последнее на самом деле не является функцией, но, надеюсь, вы меня поняли) . Помимо самих типов, в Julia я обычно ожидаю, что первые будут «функциональными», в то время как вторая форма часто включает в себя потенциальные побочные эффекты, особенно во втором выражении.

РЕДАКТИРОВАТЬ: думая об этом больше, проблема здесь полностью связана с побочными эффектами и потоком программы. Всем довольно легко понять, что «функциональное» использование && — это оптимизация & . Относительно трудно примириться с тем, что они совершенно разные для нечистых выражений.

В некоторых случаях я думаю, что «приоритет» более ясен с if a then b :

guard && c += 1    # probably an error because it's parsed as (guard && c) += 1
guard && (c += 1)  # parentheses required 

if guard then c += 1  # no ambiguity here

Также подсветка синтаксиса в редакторах поможет пометить if в начале выражения.

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

Следует отметить, что _есть много_ прецедентов для синтаксиса if-then-else :

И этот синтаксис можно использовать для однострочников на всех вышеперечисленных языках.

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

Мне кажется, что варианты короткого замыкания '&&' и '||' используются, потому что нам нужны простые операторы if в одной строке, без точек с запятой. Но короткое замыкание похоже на исправление, которое создает другую проблему: человеку трудно понять и проанализировать этот синтаксис, не ознакомившись с ним раньше или зная, что второе выражение оценивается только тогда, когда это необходимо. Неинтуитивное чтение (как человека), по-видимому, связано как с визуальными, так и с логическими несовершенствами с коротким замыканием. Даже кажется, что после того, как вы узнали, что это значит, это может быть сложнее, чем должно быть, читать.

Если не ошибаюсь, обе проблемы можно решить макросом:

@if результат условия

Отрицание может быть обработано с помощью ! перед условием или, альтернативно, макросом @ifnot . Это только я, или это не двусмысленно для компьютера, легко читается для человека, и все в одной строке?

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

^ Полностью с этим согласен.

@if результат условия

Вы уже можете сделать следующее, что выглядит почти так же:

if condition result end

Ниже приведен макрос для полного синтаксиса if-then-else. Однако, поскольку if и else являются зарезервированными ключевыми словами, вместо них макрос использует If , Then и Else .

syntax_error() = error("Valid syntax is either `<strong i="20">@If</strong> cond Then ex` or `<strong i="21">@If</strong> cond Then ex1 Else ex2`")

function If(exprs...)
    n_args = length(exprs)

    if n_args == 3
        if exprs[2] != :Then
            syntax_error()
        end

        ex = quote
            if $(exprs[1])
                $(exprs[3])
            end
        end
    elseif n_args == 5
        if ( exprs[2] != :Then ) || ( exprs[4] != :Else )
            syntax_error()
        end

        ex = quote
            if $(exprs[1])
                $(exprs[3])
            else
                $(exprs[5])
            end
        end
    else
        syntax_error()
    end

    return esc(ex)
end

macro If(exprs...)
    If(exprs...)
end

foo(x) = <strong i="22">@If</strong> x > 0 Then println("greater than zero") Else println("less than zero")

А здесь мы видим foo в действии:

julia> foo(3)
greater than zero

julia> foo(-3)
less than zero

Я бы предпочел что-то вроде

x0 = 1
x1 = 2
x3 = 3 when y>0  # y>0 is evaluated first
x4 = 4

когда будет иметь меньший приоритет, чем = и работать справа налево.

Вы уже можете сделать следующее, что выглядит почти так же:

if condition result end

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

if condition result end

полностью делает использование && избыточным, так что проблем нет! Я вижу, что можно даже сделать следующее:

if condition result_1 else result_2 end

В этом случае добавить ключевое слово end , вероятно, проще, чем создать макрос. Но спасибо, что нашли время, чтобы сделать это в любом случае ^_^ Является ли хорошей идеей добавить возможность в однострочные операторы if в документации? Я вижу, что если сделать ?If<enter> , то получится уже довольно много строк... Но я чувствую, что эту функцию нужно больше рекламировать.

Что касается первоначального обсуждения, я поддерживаю добавление «Если x, то y», хотя я нахожу это немного избыточным с однострочной версией «if». Но эй, пиши код так, как это имеет для тебя смысл, верно?

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

Смежные вопросы

i-apellaniz picture i-apellaniz  ·  3Комментарии

iamed2 picture iamed2  ·  3Комментарии

StefanKarpinski picture StefanKarpinski  ·  3Комментарии

Keno picture Keno  ·  3Комментарии

TotalVerb picture TotalVerb  ·  3Комментарии