Re[11]: Про скобочки
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.04.10 12:45
Оценка:
Здравствуйте, March_rabbit, Вы писали:

VD>>Зачем запрещать? Достаточно не допускать их смеси в одном фале.

M_>не всякий редактор покажет, что стоит имеено здесь — пробел или таб

Не пользуйся "всякими" редакторами. Пользуйся полноценными. Кроме того, табы и пробелы должны контролироваться компилятором.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[17]: Про скобочки
От: Воронков Василий Россия  
Дата: 29.04.10 13:42
Оценка:
Здравствуйте, Temoto, Вы писали:

T>Ну прям и нельзя. В том же бейсике есть специальный символ для этого: '_'. Будучи оставленным на конце строки он клеит следущую с этой строкой так, что выражение не рвётся. В питоне для этого используется обратный слеш.


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

T>>>x — x это отдельный случай, кстати.

ВВ>>Почему?
T>Потому что унарный минус это такая подлая штука, которая по определению — особый случай, потому что только для чисел, а языки программирования, вроде как не только про числа.

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

T>Я бы делал синтаксис унарного минуса таким: "-x" это он, а "- x" это правая часть от "y — x". То есть пробел обязателен вокруг нормальных операторов и обязательно без пробела после унарного минуса. Тогда "x — x" не вызывает ни визуальной неоднозначности, ни грамматической.


Угу, вставил лишний пробел и получил другую программу. Не нравится что-то.

T>(тут я схитрил) на самом деле визуальную неоднозначность убирает левый операнд. "print — x" уже однозначно понятен только парсеру.


print — x однозначно не будет понятен парсеру, в том-то и дело. Парсер парсит, он не знает, какой тип у переменных, какое у них значение и пр. Это компилятору придется "колдовать", пытаясь применить следующую эвристику:

Если для типа бинарная операция недопустима, то мы считаем, что у нас два независимых выражения, а минус — это унарная операция.

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

ВВ>>Ну вот с учетом того, что все в языке есть expression, *обязательность* блока мне кажется не очень уместной. Тяжеловато будет выглядеть код, где с правой стороны от "=" тебе *придется* объявлять несколько блоков.

T>Я что-то не проследил логику. Ты не мог бы подробнее объяснить?

Логика простая, представляем, что любое выражение может находиться справа от "=". Ты вот ниже предлагаешь сделать {} обязательными. Вот как это будет выглядеть:

var x = if cond { y } else { y2 }


вместо

var x = if (cond) y else y2


Мне второй вариант как-то больше нравится.

T>Да, чёт не фонтан.

T>А если второй ':' будет другим символом?

if bar(arg) || foo(arg2, x::xs) : fooBar(x, arg::arg2) _ barFoo(xs, arg2::arg)


Опять-таки — черточка ценный ресурс
Да и не могу сказать, что стало сильно лучше. Тогда уж сделать тернарный оператор с if вначале:

if bar(arg) || foo(arg2, x::xs) ? fooBar(x, arg::arg2) : barFoo(xs, arg2::arg)


ВВ>>>>- для вызова функций

T>>>Ничего. Пустой оператор. f x
ВВ>>Для вызова функции типа x -> void все равно потребуются скобочки — или какой другой (какой, кстати?) литерал для void.
T>Либо f будет означать вызов этой функции и не потребуются.

И получаем "проблему Руби" в полный рост?

T>Что такое void, для чего нужен?


void, он же unit (такой термин понятнее?). Я в предыдущем посте писал об этом. Вызов вида: func() можно рассматривать как funName arg, где () — это особые литерал для аргумента.
Собственно, явный void тут и нужен, чтобы сделать вызов явным.

ВВ>>А запятая зачем?

ВВ>>Убери — и получится Лисп. При этом лаконичным такой синтаксис не назовешь. К тому же:
T>Запятая — инфиксный конструктор кортежа. Без неё получится лисп, да.

Да и с ней некруто. Я спрашивал тут рядом — как например описать кортеж, элементами которого являются другие кортежи? Ответь, кстати, на тот пост

T>(я хочу сказать, что да, (array a, b).length это некрасиво, но не потому что синтаксис плох, а потому что пример неудачный)


Пример, конечно, высосан из пальца, но он показывает особенность такой литеральной записи. У нее нет четко оформленного "конца". А это может вызвать реальные проблемы.
Неслучайно ведь таких синтаксисов нет. И Хаскель твой любимый в этом плане куда более традиционен.

ВВ>>И вводить какой-нибудь значок типа вбшного "_", чтобы выражения можно было переносить на разные строчки? Или как?

T>Угу. Это, опять же, кажется стрёмным на первый взгляд. На самом деле, написать '_' один раз на 100-200 строк это гораздо дешевле и чище, чем писать ';' на каждой строке.

Так не бывает, не будет он у тебя один раз на 100-200 строк. Или же ты будешь писать в ВБ-стиле, так сказать. Т.е. в столбик. А все это приведет к очень сильному распуханию программы, объявлению кучу промежуточных переменных и пр. — мне вот такой код читать куда тяжелее, например.
; на каждой строке плохо, но с ним можно бороться. Есть два варианта.

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

Т.е. такой код валиден:

var x = {
    var tmp = 2;
    tmp * 2
 }

var y = 3


Как видишь, точка с запятой только одна.
Ну и конечно не придется писать откровенно redundant точки с запятой, как это приходится делать в C#. Например тут:

Вместо:

var f = x -> { x * x; };


будет просто

var f = x -> { x * x }



2. Убрать точку с запятой на фиг вообще. Ввести такой принцип — перед всеми "простыми" выражениями (т.е. теми, которые в обычных языках только и считаются за выражения) писать специальное ключевое слово. Например, do.
Говоря другими словами, у нас теперь все конструкции языка начинаются с ключевого слова. Вуаля, конфликтов нет. Ну делаем поблажку на то, что если у нас выражение одно-единственное в блоке, то do можно не писать:

let f = x -> x * x (* это нормально, do не нужен *)

let f2 = x -> { x * x } (* и тут тоже не нужен *)

let f3 = x -> {
  var tmp = 2
  do (x * x, tmp) (* а вот тут нужен *)
}

do f3(3)

do x = y

do -x


Проблема такого подхода — do никакого смысла не несет, это просто заплатка. Он пишется и в том случае, когда вычисленное значение не используется и в том случае, когда оно используется.
Но с другой стороны — количество таких do будет гораздо меньше чем кол-во точек с запятой. Собственно, если писать "правильно", то do придется указывать лишь у значений, который возвращаются из блоков или функций (как в пример с функцией f3).

T>Лучше всего — через промежуточные имена, *потому что* выражение *сложное*. Так будет читабельнее.

T>Но если очень хочется в строку, то почему бы и нет, вроде всё позволяет.
Нет, как же позволяет, ведь у нас \n вместо скобочек, следовательно:


var res = if cond exp /*первый конфликт*/ else expr + if ... /*второй конфликт*/
Re[18]: Про скобочки
От: Temoto  
Дата: 29.04.10 14:30
Оценка:
T>>Ну прям и нельзя. В том же бейсике есть специальный символ для этого: '_'. Будучи оставленным на конце строки он клеит следущую с этой строкой так, что выражение не рвётся. В питоне для этого используется обратный слеш.

ВВ>Я писал на VB, и этот момент раздражал весьма сильно.

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

Это костыль к неоднозначности "x \n + y". Полезной смысловой нагрузки, конечно, не имеет.

А кому он упрощает жизнь это субъективная штука. Повторюсь, лично мне гораздо приятнее один раз написать '\', чем сто раз ';'.

T>>>>x — x это отдельный случай, кстати.

ВВ>>>Почему?
T>>Потому что унарный минус это такая подлая штука, которая по определению — особый случай, потому что только для чисел, а языки программирования, вроде как не только про числа.

ВВ>Ну только для чисел, и что? Какая разница? Из-за этого он создает ничуть не больше конфликтов, чем унарный оператор & (взять-значение — например, у lazy), который не только для чисел и конфликтует с бинарным &.


Ну ладно, нет разницы. "x — x" не отдельный случай, если хочешь такую терминологию.
Когда я писал парсер, унарный минус у меня был проблемой, а унарного '&' просто не было в языке.

T>>Я бы делал синтаксис унарного минуса таким: "-x" это он, а "- x" это правая часть от "y — x". То есть пробел обязателен вокруг нормальных операторов и обязательно без пробела после унарного минуса. Тогда "x — x" не вызывает ни визуальной неоднозначности, ни грамматической.


ВВ>Угу, вставил лишний пробел и получил другую программу. Не нравится что-то.


Почему-то никого не смущает, что вставив лишний пробел в строковый литерал тоже получится другая программа, хотя в HTML такой "проблемы" нет. Но, хозяин — барин, конечно.

T>>(тут я схитрил) на самом деле визуальную неоднозначность убирает левый операнд. "print — x" уже однозначно понятен только парсеру.


ВВ>print — x однозначно не будет понятен парсеру, в том-то и дело. Парсер парсит, он не знает, какой тип у переменных, какое у них значение и пр. Это компилятору придется "колдовать", пытаясь применить следующую эвристику:


ВВ>Если для типа бинарная операция недопустима, то мы считаем, что у нас два независимых выражения, а минус — это унарная операция.


ВВ>И это ты еще привел банальный пример, а в реальности случаи могут быть куда более сложными.

ВВ>Ну и под занавес — вспоминаем, что в языке динамическая типизация и посылаем всю эту эвристику в одно место, ибо она попросту невозможна.

Ладно, я ошибся словом, нужно было сказать "компилятор" вместо "парсер". Ощущение борьбы за термины опять.

ВВ>>>Ну вот с учетом того, что все в языке есть expression, *обязательность* блока мне кажется не очень уместной. Тяжеловато будет выглядеть код, где с правой стороны от "=" тебе *придется* объявлять несколько блоков.

T>>Я что-то не проследил логику. Ты не мог бы подробнее объяснить?

ВВ>Логика простая, представляем, что любое выражение может находиться справа от "=". Ты вот ниже предлагаешь сделать {} обязательными. Вот как это будет выглядеть:


ВВ>
ВВ>var x = if cond { y } else { y2 }
ВВ>


ВВ>вместо


ВВ>
ВВ>var x = if (cond) y else y2
ВВ>


ВВ>Мне второй вариант как-то больше нравится.


А мне больше нравится var x = y if cond else y2. Уже который раз ты сравниваешь два варианта: плохой, который я не предлагал и хороший, который предлагаешь ты.
Я предлагал выделять *блоки стейтментов*. А в 'if-выражении', на мой взгляд, блоки не нужны, там можно ограничиться одним выражением в каждой позиции.

T>>Да, чёт не фонтан.

T>>А если второй ':' будет другим символом?

ВВ>
ВВ>if bar(arg) || foo(arg2, x::xs) : fooBar(x, arg::arg2) _ barFoo(xs, arg2::arg)
ВВ>


ВВ>Опять-таки — черточка ценный ресурс

ВВ>Да и не могу сказать, что стало сильно лучше. Тогда уж сделать тернарный оператор с if вначале:

ВВ>
ВВ>if bar(arg) || foo(arg2, x::xs) ? fooBar(x, arg::arg2) : barFoo(xs, arg2::arg)
ВВ>


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

ВВ>>>>>- для вызова функций

T>>>>Ничего. Пустой оператор. f x
ВВ>>>Для вызова функции типа x -> void все равно потребуются скобочки — или какой другой (какой, кстати?) литерал для void.
T>>Либо f будет означать вызов этой функции и не потребуются.

ВВ>И получаем "проблему Руби" в полный рост?


Да. И это может быть вполне разумным компромиссом. Рубироидники от этой "проблемы" не плачут по ночам.

T>>Что такое void, для чего нужен?


ВВ>void, он же unit (такой термин понятнее?).


Нет, не понятнее, увы.

ВВ>Я в предыдущем посте писал об этом. Вызов вида: func() можно рассматривать как funName arg, где () — это особые литерал для аргумента.

ВВ>Собственно, явный void тут и нужен, чтобы сделать вызов явным.

Вызов функции без аргументов это единственное зачем нужен void?

ВВ>>>А запятая зачем?

ВВ>>>Убери — и получится Лисп. При этом лаконичным такой синтаксис не назовешь. К тому же:
T>>Запятая — инфиксный конструктор кортежа. Без неё получится лисп, да.

ВВ>Да и с ней некруто. Я спрашивал тут рядом — как например описать кортеж, элементами которого являются другие кортежи? Ответь, кстати, на тот пост


(извини, искать посты не охота)

Группировка выражений — скобки.

a, (b1, b2), c

T>>(я хочу сказать, что да, (array a, b).length это некрасиво, но не потому что синтаксис плох, а потому что пример неудачный)


ВВ>Пример, конечно, высосан из пальца, но он показывает особенность такой литеральной записи. У нее нет четко оформленного "конца". А это может вызвать реальные проблемы.

ВВ>Неслучайно ведь таких синтаксисов нет. И Хаскель твой любимый в этом плане куда более традиционен.

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

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

Кстати, в Flow я не делал литералы для списков и массивов вообще.

array a, b это вызов функции array с одним аргументом: кортежем a, b. Она, в данном случае, является конструктором значения из другого значения. Своего рода каст.

ВВ>>>И вводить какой-нибудь значок типа вбшного "_", чтобы выражения можно было переносить на разные строчки? Или как?

T>>Угу. Это, опять же, кажется стрёмным на первый взгляд. На самом деле, написать '_' один раз на 100-200 строк это гораздо дешевле и чище, чем писать ';' на каждой строке.

ВВ>Так не бывает, не будет он у тебя один раз на 100-200 строк. Или же ты будешь писать в ВБ-стиле, так сказать. Т.е. в столбик. А все это приведет к очень сильному распуханию программы, объявлению кучу промежуточных переменных и пр. — мне вот такой код читать куда тяжелее, например.

ВВ>; на каждой строке плохо, но с ним можно бороться. Есть два варианта.

Ну наверное не бывает. А я могу посчитать кол-во обратных слешей в своих программах. В одном проекте было 2 '\' на 811 строк кода. Может быть оно там как-то в столбик, в неугодном стиле. Несколько людей читали и понимали, на вертикальность никто не ругался.

ВВ>1. (то, что реализовано) Точка с запятой является необязательной в том случае, если выражение является последним в блоке или же если оно следует сразу после выражением, которое заканчивается на }


ВВ>2. Убрать точку с запятой на фиг вообще. Ввести такой принцип — перед всеми "простыми" выражениями (т.е. теми, которые в обычных языках только и считаются за выражения) писать специальное ключевое слово. Например, do.

ВВ>Говоря другими словами, у нас теперь все конструкции языка начинаются с ключевого слова. Вуаля, конфликтов нет. Ну делаем поблажку на то, что если у нас выражение одно-единственное в блоке, то do можно не писать:

ВВ>Проблема такого подхода — do никакого смысла не несет, это просто заплатка. Он пишется и в том случае, когда вычисленное значение не используется и в том случае, когда оно используется.

ВВ>Но с другой стороны — количество таких do будет гораздо меньше чем кол-во точек с запятой. Собственно, если писать "правильно", то do придется указывать лишь у значений, который возвращаются из блоков или функций (как в пример с функцией f3).

Да, отсутствие смысла в do режет глаз. Такая же заплатка, как '_' или '\' только с другой стороны.

T>>Лучше всего — через промежуточные имена, *потому что* выражение *сложное*. Так будет читабельнее.

T>>Но если очень хочется в строку, то почему бы и нет, вроде всё позволяет.
ВВ>Нет, как же позволяет, ведь у нас \n вместо скобочек, следовательно:

Поправка: '\n' вместо ';', а не скобочек. Отступы вместо фигурных скобок *вокруг блоков*.

ВВ>
ВВ>var res = if cond exp /*первый конфликт*/ else expr + if ... /*второй конфликт*/
ВВ>


Я не вижу конфликта при такой грамматике:

if → "if" expr expr "else" expr
expr → atom | if | atom op atom | ...
atom → number | string | ...
op → "+" | "-" | ...
Re[19]: Про скобочки
От: Воронков Василий Россия  
Дата: 29.04.10 15:09
Оценка: +1
Здравствуйте, Temoto, Вы писали:

T>Ну ладно, нет разницы. "x — x" не отдельный случай, если хочешь такую терминологию.

T>Когда я писал парсер, унарный минус у меня был проблемой, а унарного '&' просто не было в языке.

А унарный плюс был?

T>>>Я бы делал синтаксис унарного минуса таким: "-x" это он, а "- x" это правая часть от "y — x". То есть пробел обязателен вокруг нормальных операторов и обязательно без пробела после унарного минуса. Тогда "x — x" не вызывает ни визуальной неоднозначности, ни грамматической.


ВВ>>Угу, вставил лишний пробел и получил другую программу. Не нравится что-то.


T>Почему-то никого не смущает, что вставив лишний пробел в строковый литерал тоже получится другая программа, хотя в HTML такой "проблемы" нет. Но, хозяин — барин, конечно.


Все эти варианты — довольно хитрая эвристика, которая по сути будет догадываться, как рассматривать то или иное выражение. А раз мы догадываемся, то будет и ошибаться. И программа будет работать не так, как "выглядит".
Аналогичная проблема есть у джава-скрипта с его алгоритмом автодополнения пропущенных ; который создает больше проблем решает.

Грамматика с обязательным ; хороша хотя бы тем, что она однозначна. Однозначностью жертвовать не хочется.

ВВ>>И это ты еще привел банальный пример, а в реальности случаи могут быть куда более сложными.

ВВ>>Ну и под занавес — вспоминаем, что в языке динамическая типизация и посылаем всю эту эвристику в одно место, ибо она попросту невозможна.
T>Ладно, я ошибся словом, нужно было сказать "компилятор" вместо "парсер". Ощущение борьбы за термины опять.

Это не борьба за термины. Неважно, кто занимается этой эвристикой — парсер или компилятор. Важно в данном случае то, что такая эвристика попросту невозможна в языке с динамической типизацией
Понимаешь — не термины виноваты, просто предложенный тобой вариант сделать нельзя.

Единственное, что можно — это уже в рантайме пытаться как-то определять смысл выражений, т.е. виртуальная машина вместо того, чтобы выполнять тупые pop-ы и nop-ы, будет эвристики делать. То, что производительность упадет ниже плинтуса это понятно сразу. Хотя даже еще не совсем понятно, как это вообще реализовать.

Наконец опять — мы *догадываемся* о том, что хотел пользователь. А может, он хотел из функции целое вычесть? Думал, что таким образом можно декаррирование сделать? Или просто переменные перепутал? А мы ему в ответ выполним какую-то хрень. По этому поводу опять бейсик вспоминается — если мы не уверены, что хотел программист, то давайте угадаем. На практике это создает больше проблем, чем решает.

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

T>А мне больше нравится var x = y if cond else y2. Уже который раз ты сравниваешь два варианта: плохой, который я не предлагал и хороший, который предлагаешь ты.


Ты же предлагал там где-то ниже сделать фигурные скобочки для блока if обязательными.
А var x = y if cond else y2 как будет выглядеть в качестве стейтмента?

cout "Hello, world!"  
  if cond 
  else 
cout "Goodbuy, world!"


? Что-то не то...

T>Я предлагал выделять *блоки стейтментов*. А в 'if-выражении', на мой взгляд, блоки не нужны, там можно ограничиться одним выражением в каждой позиции.


А если нужно несколько выражений внутри if?

T>Мне принципиально не нравится вся эта запись в одну строку. Слишком много смысла в одной строке. И она неминуемо будет очень длинной в реальном коде.


Я специально записываю все одну строку. Нравится или не нравится — другой вопрос. Но ты в своих примерах хитришь. Речь же идет о символах, с помощью которых можно заменить if/else. Ты же оформляешь свои примеры с разбиением на строки и фактически у тебя разделением логических частей выражения являются не эти диковинные закорючки, а перевод каретки. Потому и выглядит все хорошо.
А когда записываешь в одну строку — независимо от стилистических предпочтений, — то сразу видно, как оно там на самом-то деле.

ВВ>>>>>>- для вызова функций

T>>>>>Ничего. Пустой оператор. f x
ВВ>>>>Для вызова функции типа x -> void все равно потребуются скобочки — или какой другой (какой, кстати?) литерал для void.
T>>>Либо f будет означать вызов этой функции и не потребуются.
ВВ>>И получаем "проблему Руби" в полный рост?
T>Да. И это может быть вполне разумным компромиссом. Рубироидники от этой "проблемы" не плачут по ночам.

Компромиссом между чем и чем? Не делаем функции first class objects, чтобы избавиться от пары скобочек?
Честно, мне кажется, что это перебор. Да и совершенно неприемлимо для функционального языка.

T>>>Что такое void, для чего нужен?

ВВ>>void, он же unit (такой термин понятнее?).
T>Нет, не понятнее, увы.

unit — это то значение, которое в языках группы ML возвращают некоторые выражение. Например, let binding.

ВВ>>Я в предыдущем посте писал об этом. Вызов вида: func() можно рассматривать как funName arg, где () — это особые литерал для аргумента.

ВВ>>Собственно, явный void тут и нужен, чтобы сделать вызов явным.
T>Вызов функции без аргументов это единственное зачем нужен void?

В данном контексте — да.

T>(извини, искать посты не охота)

T>Группировка выражений — скобки.
T>a, (b1, b2), c

Ну т.е. экономия на скобочках в данном случае получается незначительной?

T>Кстати, в Flow я не делал литералы для списков и массивов вообще.

T>array a, b это вызов функции array с одним аргументом: кортежем a, b. Она, в данном случае, является конструктором значения из другого значения. Своего рода каст.

А пустой массив как создать?
А как, например, делать паттерн-матчинг по списку, если нет литерала списка?
Как к голове списка прибавить другое значение?

T>Да, отсутствие смысла в do режет глаз. Такая же заплатка, как '_' или '\' только с другой стороны.


А вариант с "не всегда обязательными" ; не решает проблему излишних точек с запятой?

T>Я не вижу конфликта при такой грамматике:

T>if → "if" expr expr "else" expr
T>expr → atom | if | atom op atom | ...
T>atom → number | string | ...
T>op → "+" | "-" | ...

По этой грамматике у тебя такое выражение невозможно: expr + expr. Т.е. на практике даже такое не будет работать: (2 + 3) + 4, потому что (2 + 3) — это не atom.
Т.е. это попросту не "боевая" грамматика.
И я уже говорил выше, что если грамматика языка позволяет записать expr expr без конфликтов, то круглые скобочки и точка с запятой автоматически идут в лес. Но с Си-подобной грамматикой это невозможно. Этого можно добиться если:

— Выкинуть пост и пре инкремент и декрементом на фиг
— Ввести постфиксную запись для унарных операторов или обязательные скобочки
— Сделать разный синтаксис вызова функции и создания кортежа
— Сделать разный синтаксис для литерала списка и индексера
— ... можем быть, что-то еще
Re[20]: Про скобочки
От: Temoto  
Дата: 29.04.10 15:43
Оценка:
T>>Ну ладно, нет разницы. "x — x" не отдельный случай, если хочешь такую терминологию.
T>>Когда я писал парсер, унарный минус у меня был проблемой, а унарного '&' просто не было в языке.

ВВ>А унарный плюс был?


Не-а.

T>>>>Я бы делал синтаксис унарного минуса таким: "-x" это он, а "- x" это правая часть от "y — x". То есть пробел обязателен вокруг нормальных операторов и обязательно без пробела после унарного минуса. Тогда "x — x" не вызывает ни визуальной неоднозначности, ни грамматической.


ВВ>>>Угу, вставил лишний пробел и получил другую программу. Не нравится что-то.


T>>Почему-то никого не смущает, что вставив лишний пробел в строковый литерал тоже получится другая программа, хотя в HTML такой "проблемы" нет. Но, хозяин — барин, конечно.


ВВ>Все эти варианты — довольно хитрая эвристика, которая по сути будет догадываться, как рассматривать то или иное выражение. А раз мы догадываемся, то будет и ошибаться. И программа будет работать не так, как "выглядит".

ВВ>Аналогичная проблема есть у джава-скрипта с его алгоритмом автодополнения пропущенных ; который создает больше проблем решает.

ВВ>Грамматика с обязательным ; хороша хотя бы тем, что она однозначна. Однозначностью жертвовать не хочется.


И точно тем же самым она плоха, потому что ты можешь вставить ';' там, где "не надо" и программа будет работать не так как выглядит. Это надо давать людям инструмент, смотреть как они пользуются, какие ошибки возникают. А то получается результаты исследования на бумаге. Заведомо оторваны от реальности.

ВВ>>>И это ты еще привел банальный пример, а в реальности случаи могут быть куда более сложными.

ВВ>>>Ну и под занавес — вспоминаем, что в языке динамическая типизация и посылаем всю эту эвристику в одно место, ибо она попросту невозможна.
T>>Ладно, я ошибся словом, нужно было сказать "компилятор" вместо "парсер". Ощущение борьбы за термины опять.

ВВ>Это не борьба за термины. Неважно, кто занимается этой эвристикой — парсер или компилятор. Важно в данном случае то, что такая эвристика попросту невозможна в языке с динамической типизацией

ВВ>Понимаешь — не термины виноваты, просто предложенный тобой вариант сделать нельзя.

Ну подумаешь "print — x" кинет исключение во время работы, а не во время компиляции. О каких эвристиках речь вобще? Какая тут неоднозначность?

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


T>>А мне больше нравится var x = y if cond else y2. Уже который раз ты сравниваешь два варианта: плохой, который я не предлагал и хороший, который предлагаешь ты.


ВВ>Ты же предлагал там где-то ниже сделать фигурные скобочки для блока if обязательными.

ВВ>А var x = y if cond else y2 как будет выглядеть в качестве стейтмента?

Вот '=' это инфиксный стейтмент.

ВВ>
ВВ>cout "Hello, world!"  
ВВ>  if cond 
ВВ>  else 
ВВ>cout "Goodbuy, world!"
ВВ>


ВВ>? Что-то не то...


Ну да. Ты опять придумываешь стрёмные примеры.

cout "Hello, world!" if cond else "Goodbye world!"

T>>Я предлагал выделять *блоки стейтментов*. А в 'if-выражении', на мой взгляд, блоки не нужны, там можно ограничиться одним выражением в каждой позиции.


ВВ>А если нужно несколько выражений внутри if?


Тогда это не выражение. Определи семантику выражения "несколько выражений" пожалуйста. Чему оно равно, как вычислять.

T>>Мне принципиально не нравится вся эта запись в одну строку. Слишком много смысла в одной строке. И она неминуемо будет очень длинной в реальном коде.


ВВ>Я специально записываю все одну строку. Нравится или не нравится — другой вопрос. Но ты в своих примерах хитришь. Речь же идет о символах, с помощью которых можно заменить if/else. Ты же оформляешь свои примеры с разбиением на строки и фактически у тебя разделением логических частей выражения являются не эти диковинные закорючки, а перевод каретки. Потому и выглядит все хорошо.

ВВ>А когда записываешь в одну строку — независимо от стилистических предпочтений, — то сразу видно, как оно там на самом-то деле.

Ну да, видишь, обязательный перевод строки лечит проблемы которые "там на самом-то деле".

ВВ>>>>>>>- для вызова функций

T>>>>>>Ничего. Пустой оператор. f x
ВВ>>>>>Для вызова функции типа x -> void все равно потребуются скобочки — или какой другой (какой, кстати?) литерал для void.
T>>>>Либо f будет означать вызов этой функции и не потребуются.
ВВ>>>И получаем "проблему Руби" в полный рост?
T>>Да. И это может быть вполне разумным компромиссом. Рубироидники от этой "проблемы" не плачут по ночам.

ВВ>Компромиссом между чем и чем? Не делаем функции first class objects, чтобы избавиться от пары скобочек?

ВВ>Честно, мне кажется, что это перебор. Да и совершенно неприемлимо для функционального языка.

Ещё раз, у рубироидников всё нормально. Это опыт многих людей, многих лет. А ты вот так из пальца говоришь, что это неприемлимо.

T>>>>Что такое void, для чего нужен?

ВВ>>>void, он же unit (такой термин понятнее?).
T>>Нет, не понятнее, увы.

ВВ>unit — это то значение, которое в языках группы ML возвращают некоторые выражение. Например, let binding.


ВВ>>>Я в предыдущем посте писал об этом. Вызов вида: func() можно рассматривать как funName arg, где () — это особые литерал для аргумента.

ВВ>>>Собственно, явный void тут и нужен, чтобы сделать вызов явным.
T>>Вызов функции без аргументов это единственное зачем нужен void?

ВВ>В данном контексте — да.


Ну тогда можно префиксный оператор 'call', например.

T>>(извини, искать посты не охота)

T>>Группировка выражений — скобки.
T>>a, (b1, b2), c

ВВ>Ну т.е. экономия на скобочках в данном случае получается незначительной?


В контексте кортежей экономия в любом случае будет максимум — 2 скобки с каждого кортежа. Поскольку в выражениях редко встречается несколько кортежей сразу, то да, в каком-то приближении можно сказать, что она всегда незначительна.
А если из программы убрать 800 скобок, то вроде уже и значительно.
А если из программы в 14500 символов убрать 800 скобок, то опять незначительно.
Это игра слов.

T>>Кстати, в Flow я не делал литералы для списков и массивов вообще.

T>>array a, b это вызов функции array с одним аргументом: кортежем a, b. Она, в данном случае, является конструктором значения из другого значения. Своего рода каст.

ВВ>А пустой массив как создать?


array

ВВ>А как, например, делать паттерн-матчинг по списку, если нет литерала списка?


Точно так же, как делать патерн-матчинг по юзерскому типу с юзерским конструктором.

case foo of
list args → print args

ВВ>Как к голове списка прибавить другое значение?


xs = list 1, 2
(head xs) + 3 # 4

T>>Да, отсутствие смысла в do режет глаз. Такая же заплатка, как '_' или '\' только с другой стороны.


ВВ>А вариант с "не всегда обязательными" ; не решает проблему излишних точек с запятой?


Ты же сам критиковал эвристику жаваскрипта. Здесь то же самое, только упрощено.
По сути, они всегда обязательны между двумя стейтментами. Ну ладно, из 10 строк в одной ты не пишешь ';'. Ну ладно, к этому складывается ещё несколько мест, где тоже не пишешь. Но программист, который не писал парсер не держит в голове полную грамматику языка. Ему на бизнес-задаче надо концентрироваться, а не на оптимальной расстановке ';', поэтому такой вариант не катит, как сложный для понимания.
Я в жаваскрипте пишу ';' только потому что это единственный для меня способ *надёжно* сообщить интепретатору единственный смысл. Чтоб в каких-то местах пропускать разделитель мне уже нужно думать, мол, а разрешено ли это здесь.

T>>Я не вижу конфликта при такой грамматике:

T>>if → "if" expr expr "else" expr
T>>expr → atom | if | atom op atom | ...
T>>atom → number | string | ...
T>>op → "+" | "-" | ...

ВВ>По этой грамматике у тебя такое выражение невозможно: expr + expr. Т.е. на практике даже такое не будет работать: (2 + 3) + 4, потому что (2 + 3) — это не atom.

ВВ>Т.е. это попросту не "боевая" грамматика.

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

ВВ>И я уже говорил выше, что если грамматика языка позволяет записать expr expr без конфликтов, то круглые скобочки и точка с запятой автоматически идут в лес. Но с Си-подобной грамматикой это невозможно. Этого можно добиться если:


ВВ>- Выкинуть пост и пре инкремент и декрементом на фиг

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

У меня не было терма expr expr. Я вообще затрудняюсь придумать что он должен значить.
expr op expr, где op = "" я могу понять. А вот так просто expr expr это какой-то нонсенс.
Re[2]: Про скобочки
От: Gaperton http://gaperton.livejournal.com
Дата: 29.04.10 15:45
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

ВВ>>А как бы вы отнеслись к сокращению "скобочности" синтаксиса? Хотя бы в выражениях. Например, вместо


PD>И получился у тебя Паскаль — почти 1:1


У него получился Google Go. Один в один, без почти.
Re[21]: Про скобочки
От: Воронков Василий Россия  
Дата: 29.04.10 16:08
Оценка:
Здравствуйте, Temoto, Вы писали:

ВВ>>Грамматика с обязательным ; хороша хотя бы тем, что она однозначна. Однозначностью жертвовать не хочется.

T>И точно тем же самым она плоха, потому что ты можешь вставить ';' там, где "не надо" и программа будет работать не так как выглядит. Это надо давать людям инструмент, смотреть как они пользуются, какие ошибки возникают. А то получается результаты исследования на бумаге. Заведомо оторваны от реальности.

Если я вставлю ";" там, где не надо — а кстати, пример можно? а мне сложновато представить, к тому же во многих случаях лишние ";" вполне допускаются, — то по тексту программу будет видно, где ошибка. В случае с print — x и прочими радостями — не видно. Так что разница большая на самом деле.

T>Ну подумаешь "print — x" кинет исключение во время работы, а не во время компиляции. О каких эвристиках речь вобще? Какая тут неоднозначность?


Эээ, ты издеваешься? Неоднозначность простая. Ты не забыл о чем мы говорили? Как рассматривать выражение:

print
-x

Ты предлагал ввести некий анализ, с помощью которого можно определить, что это на самом деле не вычитание x из print, а два выражения.
Так вот — в динамическом языке такой анализ невозможен.

ВВ>>? Что-то не то...

T>Ну да. Ты опять придумываешь стрёмные примеры.
T>cout "Hello, world!" if cond else "Goodbye world!"

Нормальный пример. Я придумываю пример, в котором условное выражение находит не "справа", а "слева", т.е. само по себе является стейтментом. Предположим, что его части вообще никакого полезного значения не возвращают.
Вот другой пример:

cout myStupidFunc(...)
  if cond 
  else 
throw "Error!"


T>>>Я предлагал выделять *блоки стейтментов*. А в 'if-выражении', на мой взгляд, блоки не нужны, там можно ограничиться одним выражением в каждой позиции.

ВВ>>А если нужно несколько выражений внутри if?
T>Тогда это не выражение. Определи семантику выражения "несколько выражений" пожалуйста. Чему оно равно, как вычислять.

Все есть выражение. Даже блок {} — это выражение. В языке же нет разделения на стейтменты и экспрешины, поэтому все твои примеры неизбежно надо рассматривать и в роли экспрешинов и в роли стейтментов.

T>Ну да, видишь, обязательный перевод строки лечит проблемы которые "там на самом-то деле".


Ну т.е. под видом всяких : | _ ты как бы "зашифровано" предлагал перевод строки?

ВВ>>Компромиссом между чем и чем? Не делаем функции first class objects, чтобы избавиться от пары скобочек?

ВВ>>Честно, мне кажется, что это перебор. Да и совершенно неприемлимо для функционального языка.
T>Ещё раз, у рубироидников всё нормально. Это опыт многих людей, многих лет. А ты вот так из пальца говоришь, что это неприемлимо.

А у людей всегда все нормально. У ПХП-ников все нормально. У Сишников тоже все нормально. У всех все нормально. И это опыт многих людей и многих лет. Это *всегда* опыт многих людей и многих лет. Даже когда речь идет о кривом дизайне и кривых решениях.

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

Опять же, напомню тебе твои же слова — зачем вводить в язык необоснованные ограничения? Как например невозможность передать функцию как значение. Причем *только* из-за синтаксиса.

T>>>Вызов функции без аргументов это единственное зачем нужен void?

ВВ>>В данном контексте — да.
T>Ну тогда можно префиксный оператор 'call', например.

А тип функции без параметров какой? Все равно же это type -> void. Почему бы явно это не описать? Да и какую проблему решает префиксный оператор? Избавляемся от скобок справа, вводим ключевой слово слева?

T>В контексте кортежей экономия в любом случае будет максимум — 2 скобки с каждого кортежа. Поскольку в выражениях редко встречается несколько кортежей сразу, то да, в каком-то приближении можно сказать, что она всегда незначительна.

T>А если из программы убрать 800 скобок, то вроде уже и значительно.
T>А если из программы в 14500 символов убрать 800 скобок, то опять незначительно.
T>Это игра слов.

Ты понимаешь, скобочки хочется не просто убрать. Хочется не убрать вместе со скобочками что-нибудь еще, как например, first class функции.

ВВ>>А пустой массив как создать?

T>array

Описал бы лучше полностью свой синтаксис с примерами.

ВВ>>А вариант с "не всегда обязательными" ; не решает проблему излишних точек с запятой?

T>Ты же сам критиковал эвристику жаваскрипта. Здесь то же самое, только упрощено.

Здесь не то же самое. Если ты так говоришь, то просто не понимаешь, что на самом деле происходит в джава-скрипте. Там в зависимости от версии алгоритм добавления ";" такое выражение:


return 
{
  Value1: ...,
  Value2: ...
}



можешь превратить в такое:


return;
{
  Value1: ...,
  Value2: ...
}



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

T>По сути, они всегда обязательны между двумя стейтментами.


Вовсе нет. Даже в Си это не так.

T>>>Я не вижу конфликта при такой грамматике:

T>>>if → "if" expr expr "else" expr
T>>>expr → atom | if | atom op atom | ...
T>>>atom → number | string | ...
T>>>op → "+" | "-" | ...

ВВ>>По этой грамматике у тебя такое выражение невозможно: expr + expr. Т.е. на практике даже такое не будет работать: (2 + 3) + 4, потому что (2 + 3) — это не atom.

ВВ>>Т.е. это попросту не "боевая" грамматика.

T>омг ну добавь "(" expr ")" в atom, это же очевидно.


ОК. Тогда такое выражение невозможно 2 + 3 + 4.
Что еще такое "очевидное" добавить в грамматику?

T>Да, она не боевая. Какая разница? Я просто хотел сказать, что в указанном тобой выражении не вижу конфликтов при таком-то условии (грамматика). А ты, блин, вместо того чтоб показать при каких условиях там таки есть конфликт, ищешь несостоятельность грамматики.


Разница большая. Можно придумать грамматику из трех строк, в которой конфликтов не будет. Но в реальной грамматике, где учитываются все операции — конфликты будут. Зачем приводить пример такой игрушечной грамматики без конфликтов? Что он показывает?

T>У меня не было терма expr expr. Я вообще затрудняюсь придумать что он должен значить.

T>expr op expr, где op = "" я могу понять. А вот так просто expr expr это какой-то нонсенс.

Ну как же, вот он:

if → "if" expr expr "else" expr
Re: Про скобочки
От: RiNSpy  
Дата: 29.04.10 16:08
Оценка:
Поддерживаю.

Синтаксический оверхед, однако.
Re[3]: Про скобочки
От: Воронков Василий Россия  
Дата: 29.04.10 16:37
Оценка:
Здравствуйте, Gaperton, Вы писали:

PD>>И получился у тебя Паскаль — почти 1:1

G>У него получился Google Go. Один в один, без почти.

В Гоу фигурные скобки обязательны, а круглые — нет. Я фигурные скобки не трогаю, рассматриваю вариант вместо круглых использовать другой токен, вроде 'do' или 'then'. И сдается мне, что на Гоу это похоже слабо.
Re[22]: Про скобочки
От: Temoto  
Дата: 29.04.10 17:28
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, Temoto, Вы писали:


ВВ>>>Грамматика с обязательным ; хороша хотя бы тем, что она однозначна. Однозначностью жертвовать не хочется.

T>>И точно тем же самым она плоха, потому что ты можешь вставить ';' там, где "не надо" и программа будет работать не так как выглядит. Это надо давать людям инструмент, смотреть как они пользуются, какие ошибки возникают. А то получается результаты исследования на бумаге. Заведомо оторваны от реальности.

ВВ>Если я вставлю ";" там, где не надо — а кстати, пример можно? а мне сложновато представить, к тому же во многих случаях лишние ";" вполне допускаются, — то по тексту программу будет видно, где ошибка. В случае с print — x и прочими радостями — не видно. Так что разница большая на самом деле.


Все те же примеры, которые ты приводил про перевод строки.

x; -y

arr;[index]

print; x

T>>Ну подумаешь "print — x" кинет исключение во время работы, а не во время компиляции. О каких эвристиках речь вобще? Какая тут неоднозначность?


ВВ>Эээ, ты издеваешься? Неоднозначность простая. Ты не забыл о чем мы говорили? Как рассматривать выражение:


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

ВВ>print

ВВ>-x

ВВ>Ты предлагал ввести некий анализ, с помощью которого можно определить, что это на самом деле не вычитание x из print, а два выражения.

ВВ>Так вот — в динамическом языке такой анализ невозможен.

Я точно предлагал анализ?

ВВ>>>? Что-то не то...

T>>Ну да. Ты опять придумываешь стрёмные примеры.
T>>cout "Hello, world!" if cond else "Goodbye world!"

ВВ>Нормальный пример. Я придумываю пример, в котором условное выражение находит не "справа", а "слева", т.е. само по себе является стейтментом. Предположим, что его части вообще никакого полезного значения не возвращают.

ВВ>Вот другой пример:

Если его части полезного значения не возвращают, значит это тут не нужно if-выражение.
Как вариант, можно отдельно иметь классический if-statement.

Ты смешиваешь тернарный условный оператор (if-else-expression) и if-statement. Они для разных целей используются. Поэтому один выглядит уродливо там, где нужно применить второй. Это нормально.

T>>>>Я предлагал выделять *блоки стейтментов*. А в 'if-выражении', на мой взгляд, блоки не нужны, там можно ограничиться одним выражением в каждой позиции.

ВВ>>>А если нужно несколько выражений внутри if?
T>>Тогда это не выражение. Определи семантику выражения "несколько выражений" пожалуйста. Чему оно равно, как вычислять.

ВВ>Все есть выражение. Даже блок {} — это выражение. В языке же нет разделения на стейтменты и экспрешины, поэтому все твои примеры неизбежно надо рассматривать и в роли экспрешинов и в роли стейтментов.


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

T>>Ну да, видишь, обязательный перевод строки лечит проблемы которые "там на самом-то деле".


ВВ>Ну т.е. под видом всяких : | _ ты как бы "зашифровано" предлагал перевод строки?


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

if not foo: continue # это единственный случай, где я сомневаюсь: ставить перевод строки или нет. И когда всё-таки поставлю тоже выглядит нормально.

ВВ>>>Компромиссом между чем и чем? Не делаем функции first class objects, чтобы избавиться от пары скобочек?

ВВ>>>Честно, мне кажется, что это перебор. Да и совершенно неприемлимо для функционального языка.
T>>Ещё раз, у рубироидников всё нормально. Это опыт многих людей, многих лет. А ты вот так из пальца говоришь, что это неприемлимо.

ВВ>А у людей всегда все нормально. У ПХП-ников все нормально. У Сишников тоже все нормально. У всех все нормально. И это опыт многих людей и многих лет. Это *всегда* опыт многих людей и многих лет. Даже когда речь идет о кривом дизайне и кривых решениях.


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

От всех сишников, в один голос: рутина, рутина, нет неймспейсов, рутина, сегфолты, рутина. Действительно, на скобки никто не жалуется.

ВВ>Ты, я так понимаю, в свой язык решил добавить такую возможность, оттого и выступаешь с ее апологией. Я бы не советовал. Если только язык не удовлетворяет хотя бы одному из требований: 1) полностью ленивый и 2) чистый функциональный. Синтаксис — это одно. Но невозможность нормально писать в функциональном стиле, использовать функции высшего порядке, только потому что кто-то экономил на скобках или еще на чем — это не вариант.

ВВ>Проще запретить объявлять функции без параметров вообще, это и лучше.

ВВ>Опять же, напомню тебе твои же слова — зачем вводить в язык необоснованные ограничения? Как например невозможность передать функцию как значение. Причем *только* из-за синтаксиса.


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

T>>>>Вызов функции без аргументов это единственное зачем нужен void?

ВВ>>>В данном контексте — да.
T>>Ну тогда можно префиксный оператор 'call', например.

ВВ>А тип функции без параметров какой? Все равно же это type -> void. Почему бы явно это не описать? Да и какую проблему решает префиксный оператор? Избавляемся от скобок справа, вводим ключевой слово слева?


Тип функции без параметров: type.
type → void это отображение какого-то типа на одно значение void, то есть функция-константа, которая с любым аргументом возвращает одно значение.

Избавляемся от void, вводим ключевое слово для редкого случая — вызов нулларной функции.
Опять, это один из многих вариантов, я не продвигаю конкретно 'call'.

T>>В контексте кортежей экономия в любом случае будет максимум — 2 скобки с каждого кортежа. Поскольку в выражениях редко встречается несколько кортежей сразу, то да, в каком-то приближении можно сказать, что она всегда незначительна.

T>>А если из программы убрать 800 скобок, то вроде уже и значительно.
T>>А если из программы в 14500 символов убрать 800 скобок, то опять незначительно.
T>>Это игра слов.

ВВ>Ты понимаешь, скобочки хочется не просто убрать. Хочется не убрать вместе со скобочками что-нибудь еще, как например, first class функции.


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

ВВ>>>А пустой массив как создать?

T>>array

ВВ>Описал бы лучше полностью свой синтаксис с примерами.


http://s.temoto.ru/flow/spec.rst
Здесь есть очень старая версия. Там, может быть, всё ещё есть []. Но вроде бы должны быть примеры других конструкций типа bytes "foo".

ВВ>>>А вариант с "не всегда обязательными" ; не решает проблему излишних точек с запятой?

T>>Ты же сам критиковал эвристику жаваскрипта. Здесь то же самое, только упрощено.

ВВ>Здесь не то же самое. Если ты так говоришь, то просто не понимаешь, что на самом деле происходит в джава-скрипте.


Да, всё верно. Я сказал

Здесь то же самое, только упрощено.

а ты пропустил половину предложения.

Под "здесь то же самое" я подразумевал именно "не всегда обязательные ';'".

ВВ>и получишь кукишь с маслом вместо значения из функции.

ВВ>Описанный мной алгоритм очень прост — у последнего выражения в блоке можно опустить точку с запятой. А можно и не опускать. Можно дописать еще и пару лишних. Никакой неоднозначности не будет.
ВВ>По-моему запомнить это совсем несложно.

Запомнить несложно. Сложно думать об этом, применять это, когда пишешь бизнес-логику, а не абстрактный код для примеров. Убрал второе выражение из двух в блоке и вроде бы можно убрать ';' вместе с ним. Чем думать об этом — проще всегда ставить ';' там где надо и там где можно без него.

T>>Да, она не боевая. Какая разница? Я просто хотел сказать, что в указанном тобой выражении не вижу конфликтов при таком-то условии (грамматика). А ты, блин, вместо того чтоб показать при каких условиях там таки есть конфликт, ищешь несостоятельность грамматики.


ВВ>Разница большая. Можно придумать грамматику из трех строк, в которой конфликтов не будет. Но в реальной грамматике, где учитываются все операции — конфликты будут. Зачем приводить пример такой игрушечной грамматики без конфликтов? Что он показывает?


Он даёт базу для рассуждений в одной логике. Без него каждый волен мыслить в своей граматике и мы друг друга не поймём. Так и случилось.

T>>У меня не было терма expr expr. Я вообще затрудняюсь придумать что он должен значить.

T>>expr op expr, где op = "" я могу понять. А вот так просто expr expr это какой-то нонсенс.

ВВ>Ну как же, вот он:


ВВ>if → "if" expr expr "else" expr


Терма/продукции expr expr всё ещё нет. Ты выделил *кусок* if.
Re[4]: Про скобочки
От: Gaperton http://gaperton.livejournal.com
Дата: 29.04.10 18:19
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, Gaperton, Вы писали:


PD>>>И получился у тебя Паскаль — почти 1:1

G>>У него получился Google Go. Один в один, без почти.

ВВ>В Гоу фигурные скобки обязательны, а круглые — нет. Я фигурные скобки не трогаю, рассматриваю вариант вместо круглых использовать другой токен, вроде 'do' или 'then'. И сдается мне, что на Гоу это похоже слабо.


А ты глянь синтаксис.
http://golang.org/

Мне кажется — очень близко к твоей идее. Я бы сказал, одинакова. И мне очень понравилось — я немного порешал примеров на Го. Хорошая идея.
Re[23]: Про скобочки
От: Воронков Василий Россия  
Дата: 29.04.10 18:29
Оценка:
Здравствуйте, Temoto, Вы писали:

T>Все те же примеры, которые ты приводил про перевод строки.

T>x; -y
T>arr;[index]
T>print; x

Возвращаясь к вопросу об однозначности. Однозначность, понимаешь, такая штука — у нее всегда одно значение Вот у ";" здесь ровно одно значение. Оно всегда одно и то же.
Если вспомнить вариант, который предлагал ты — рассматривать в качестве разделителя выражений пробел. Вот, скажи, подобные конструкции равнозначны:

var x= 2
var x = 2
var x   = 2


Казалось бы, должны, так ведь? А вот подобные уже не равнозначны:

arr[index]
arr [index]


Т.е. в одном случае у нас пробел имеет одно значение, в другом — другое. Однозначности нет. Где-то лишний пробел не играет роли вообще, а где-то приведет к принципиально другой программе.
А вот у точки с запятой семантика одинакова всегда. Поэтому-то решение с пробелами мне и кажется весьма сомнительным.

ВВ>>Эээ, ты издеваешься? Неоднозначность простая. Ты не забыл о чем мы говорили? Как рассматривать выражение:

T>Не издеваюсь, просто я работаю и периодически проверяю почту. Переключение контекстов. Поэтому я так сильно за то, чтобы обсуждать подобные длинные темы в реале, с бумажкой.

Ну мне просто сложно в реале
Да и поговорил ты "с бумажкой", а нужная мысль пришла только день спустя. На форуме можешь вернуться к сообщению хоть недельной давности.

ВВ>>Ты предлагал ввести некий анализ, с помощью которого можно определить, что это на самом деле не вычитание x из print, а два выражения.

ВВ>>Так вот — в динамическом языке такой анализ невозможен.
T>Я точно предлагал анализ?

Ты писал, цитирую: "на самом деле визуальную неоднозначность убирает левый операнд. "print — x" уже однозначно понятен только парсеру."
Чтобы "парсер" что-либо понимал, ну, очевидно, анализ какой-то нужен. Конфликт есть? Есть. Надо его как-то разрешать.

T>Если его части полезного значения не возвращают, значит это тут не нужно if-выражение.

T>Как вариант, можно отдельно иметь классический if-statement.

Т.е. обратно вводить в язык разделение на statement/expression? И как будет выглядеть этот if-statement? Если его определение неконфликтно с if-expression, то мы просто получаем две равноценные по смыслу конструкцию.
Не говоря уже о том, что... ну нету просто такого разделения, все есть expression, все возвращает значение. В каких-то случаях возвращаемое значение тебе просто не нужно. Вот и все. В коде вида:

let func(x, y) = 
  {
     var res = x + y;
     ...

     if (check(res))
         cout res
     else
         throw "error";

     if (res > 0)
         res
     else
         magic_const
  }


Первый if выступает в качестве statement, а вот второй — уже в качестве expression, т.к. он становится возвращаемым значением функции func. Придется использовать разный синтаксис для них?

T>Ты смешиваешь тернарный условный оператор (if-else-expression) и if-statement. Они для разных целей используются. Поэтому один выглядит уродливо там, где нужно применить второй. Это нормально.


Еще раз — разделения на statement/expression нет. Да и тернарный оператор тоже по большому счету не нужен. Он остался лишь как наследие из старых времен — да как своего рода сахар.

T>>>>>Я предлагал выделять *блоки стейтментов*. А в 'if-выражении', на мой взгляд, блоки не нужны, там можно ограничиться одним выражением в каждой позиции.

ВВ>>>>А если нужно несколько выражений внутри if?
T>>>Тогда это не выражение. Определи семантику выражения "несколько выражений" пожалуйста. Чему оно равно, как вычислять.

Для определения нескольких выражений используется специальное выражение "блок". Вот как он выглядит:

{
  ...
}


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

ВВ>>Все есть выражение. Даже блок {} — это выражение. В языке же нет разделения на стейтменты и экспрешины, поэтому все твои примеры неизбежно надо рассматривать и в роли экспрешинов и в роли стейтментов.

T>Я снова попрошу определить семантику выражения "несколько выражений" или блока. Это кажется чем-то очевидным и естественным, на самом деле возможны разные варианты и когда ты дашь определение, у нас будет общая база.

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

T> ну если хочешь, наверное, можно так сказать, я не пытался что-то прятать

T>Просто, лично для очевидно, что большой if-else на одной строке хуже, чем на трёх.

Вопрос не о стиле форматирования ("большой if-else"), а о грамматике if-else. Большой на одной строке хуже, маленький хуже на трех — это вопросы стиля. Грамматика может либо позволять записывать if-else в одну строку, либо не позволять.

T>if not foo: continue # это единственный случай, где я сомневаюсь: ставить перевод строки или нет. И когда всё-таки поставлю тоже выглядит нормально.


Потому что ты мыслишь в категориях "есть statements, есть expressions". А если это разделение убирается, то if — это всегда просто тернарный оператор. Всегда. Не более того. Иногда удобнее на нескольких строках, но часто хорошо выглядит и на одной.
Вводить грамматику, согласно которой синтаксис некоторых expression заставляет писать их на разных строках, мне кажется плохой идеей.

T>Неправда твоя, Василий. Может быть, конечно, мы с разными пыхпыхами общались. Я от всех в один голос слышу одни и те же беды про индексацию функции, которая вернула массив, подгрузку нужных классов и пр. Стандартный набор баттхертов.


От кого слышишь? От "рубироидников"? Ты же говорил, что у них все нормально

T>От всех сишников, в один голос: рутина, рутина, нет неймспейсов, рутина, сегфолты, рутина. Действительно, на скобки никто не жалуется.


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

T>В Flow это лечится ленивостью.


Ну т.е. функцию как значение передать все же можно?

T>Я не выступаю с апологией конкретно этого подхода. Я говорю, что это разумный вариант. Один из многих других вариантов.


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

T>Тип функции без параметров: type.

T>type → void это отображение какого-то типа на одно значение void, то есть функция-константа, которая с любым аргументом возвращает одно значение.

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

T>Избавляемся от void, вводим ключевое слово для редкого случая — вызов нулларной функции.


А чем мешает void? Его наличие необходимо как только снимается разница между expressions и statements. Или опять обратно statements прикручивать?

T>http://s.temoto.ru/flow/spec.rst

T>Здесь есть очень старая версия. Там, может быть, всё ещё есть []. Но вроде бы должны быть примеры других конструкций типа bytes "foo".

Жаль описания самого языка нет, так конечно сложновато понимать, о чем речь.

T>Запомнить несложно. Сложно думать об этом, применять это, когда пишешь бизнес-логику, а не абстрактный код для примеров. Убрал второе выражение из двух в блоке и вроде бы можно убрать ';' вместе с ним. Чем думать об этом — проще всегда ставить ';' там где надо и там где можно без него.


Аналогичная эвристика используется в Немерле. Согласно твоей же логике — много людей, на протяжении лет... — и так далее, и тому подобное.

ВВ>>Разница большая. Можно придумать грамматику из трех строк, в которой конфликтов не будет. Но в реальной грамматике, где учитываются все операции — конфликты будут. Зачем приводить пример такой игрушечной грамматики без конфликтов? Что он показывает?

T>Он даёт базу для рассуждений в одной логике. Без него каждый волен мыслить в своей граматике и мы друг друга не поймём. Так и случилось.

Я не вижу этой базы. Грамматика неполная, фактически попросту неполноценная. Я из нее ничего "вынести" не могу. Если ты хотел показать, что есть грамматики для которых можно в конкретном обсуждаемом случае избежать конфликта, то я и так прекрасно понимаю, что они есть. Более того, я прекрасно понимаю — и делал это в порядке эксперимента, — как я могу модифицировать свою грамматику, чтобы убрать в данном случае конфликты.

ВВ>>if → "if" expr expr "else" expr

T>Терма/продукции expr expr всё ещё нет. Ты выделил *кусок* if.

И что? Какая разница? Два expr идут друг за другом, разделенные пробелом. Что изменится, если их перенести в отдельную продукцию? Ничего. Это та самая ситуация, о которой я говорил — есть два expr, между ними только пробел. В си-подобном синтаксисе такая конструкция невозможна без конфликтов.
Re[5]: Про скобочки
От: Воронков Василий Россия  
Дата: 29.04.10 19:15
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>А ты глянь синтаксис.

G>http://golang.org/

Я смотрел здесь — http://golang.org/doc/go_spec.html#If_statements.
Не скажу, что копал подробно. Но на основе приведенных там продукций/примеров кода складывается ощущение, что синтаксис, скажем так, с хорошим таким багажом наследия от Си (например, есть разделение на statement и expression), но некоторыми небольшими модификациями, например:

ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .


Продукция Block, соответственно, описывается как:

Block = "{" { Statement ";" } "}" .


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

А есть и странные продукции:

IfStmt    = "if" [ SimpleStmt ";" ] [ Expression ] Block [ "else" Statement ] .


Например тут такая запись валидна:

if x {
  y;
}
else 
  z;


Но такая, если верить продукции, нет:

if x
  y;
else 
  z;


Т.е. по-моему очевидно, что фигурные скобочки компенсируют отсутствие круглых.

G>Мне кажется — очень близко к твоей идее. Я бы сказал, одинакова. И мне очень понравилось — я немного порешал примеров на Го. Хорошая идея.


Может, я не увидел в Гоу чего-то, что видишь ты? О какой идее речь? Сократить количество круглых скобочек?
Но там они сокращаются за счет фигурных, я так просто не могу, это будет по меньшей мере уродливо:

var value = if x { y } else { z }


Что-то не то... Я вариант обязательности явного указания блоков не рассматривал.
А вообще примеры, которые я приводил в первом посте, взяты из OCaml.
Re[24]: Про скобочки
От: Temoto  
Дата: 29.04.10 19:31
Оценка:
T>>Все те же примеры, которые ты приводил про перевод строки.
T>>x; -y
T>>arr;[index]
T>>print; x

ВВ>Возвращаясь к вопросу об однозначности. Однозначность, понимаешь, такая штука — у нее всегда одно значение Вот у ";" здесь ровно одно значение. Оно всегда одно и то же.

ВВ>Если вспомнить вариант, который предлагал ты — рассматривать в качестве разделителя выражений пробел. Вот, скажи, подобные конструкции равнозначны:

ВВ>
ВВ>var x= 2
ВВ>var x = 2
ВВ>var x   = 2
ВВ>


ВВ>Казалось бы, должны, так ведь? А вот подобные уже не равнозначны:


ВВ>
ВВ>arr[index]
ВВ>arr [index]
ВВ>


ВВ>Т.е. в одном случае у нас пробел имеет одно значение, в другом — другое. Однозначности нет. Где-то лишний пробел не играет роли вообще, а где-то приведет к принципиально другой программе.

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

Согласно каким правилам "var x= 2" и "var x = 2" равнозначны, а "arr[index]" и "arr [index]" ­— нет?

ВВ>>>Эээ, ты издеваешься? Неоднозначность простая. Ты не забыл о чем мы говорили? Как рассматривать выражение:

T>>Не издеваюсь, просто я работаю и периодически проверяю почту. Переключение контекстов. Поэтому я так сильно за то, чтобы обсуждать подобные длинные темы в реале, с бумажкой.

ВВ>Ну мне просто сложно в реале

ВВ>Да и поговорил ты "с бумажкой", а нужная мысль пришла только день спустя. На форуме можешь вернуться к сообщению хоть недельной давности.

Очень странная защита форума. Дела, там, расстояние, это я всё понимаю. Но в реале тоже можно через неделю обсудить новую мысль.

ВВ>>>Ты предлагал ввести некий анализ, с помощью которого можно определить, что это на самом деле не вычитание x из print, а два выражения.

ВВ>>>Так вот — в динамическом языке такой анализ невозможен.
T>>Я точно предлагал анализ?

ВВ>Ты писал, цитирую: "на самом деле визуальную неоднозначность убирает левый операнд. "print — x" уже однозначно понятен только парсеру."

ВВ>Чтобы "парсер" что-либо понимал, ну, очевидно, анализ какой-то нужен. Конфликт есть? Есть. Надо его как-то разрешать.

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

T>>Если его части полезного значения не возвращают, значит это тут не нужно if-выражение.

T>>Как вариант, можно отдельно иметь классический if-statement.

ВВ>Т.е. обратно вводить в язык разделение на statement/expression? И как будет выглядеть этот if-statement? Если его определение неконфликтно с if-expression, то мы просто получаем две равноценные по смыслу конструкцию.

ВВ>Не говоря уже о том, что... ну нету просто такого разделения, все есть expression, все возвращает значение. В каких-то случаях возвращаемое значение тебе просто не нужно. Вот и все. В коде вида:

ВВ>Первый if выступает в качестве statement, а вот второй — уже в качестве expression, т.к. он становится возвращаемым значением функции func. Придется использовать разный синтаксис для них?


T>>Ты смешиваешь тернарный условный оператор (if-else-expression) и if-statement. Они для разных целей используются. Поэтому один выглядит уродливо там, где нужно применить второй. Это нормально.


ВВ>Еще раз — разделения на statement/expression нет. Да и тернарный оператор тоже по большому счету не нужен. Он остался лишь как наследие из старых времен — да как своего рода сахар.


Хакей, разделения нет. Тернарный оператор не нужен. Но if у тебя — выражение. Значит он и есть тернарный оператор. Кроме того, если if — всегда выражение, значит ты обязываешь всегда писать else (потому что иначе у ветки cond == false нет значения. Ну ладно, ты опять скажешь что значение будет вездессущий null, это мы уже обсуждали.

Тогда then — самый читаемый и консистентный вариант, раз ты в такие рамки ставишь.

T>>>>>>Я предлагал выделять *блоки стейтментов*. А в 'if-выражении', на мой взгляд, блоки не нужны, там можно ограничиться одним выражением в каждой позиции.

ВВ>>>>>А если нужно несколько выражений внутри if?
T>>>>Тогда это не выражение. Определи семантику выражения "несколько выражений" пожалуйста. Чему оно равно, как вычислять.

ВВ>Для определения нескольких выражений используется специальное выражение "блок". Вот как он выглядит:


ВВ>Блок может содержать от нуля до неограниченного кол-ва выражений. Блок сам по себе так же является выражением. Значением, которое возвращает блок, является значение последнего выражения внутри блока. Пустой блок возвращает void.


Хакей, блоки как в эрланге. Кстати я для Flow тоже думал о такой конструкции, типа do { expr; expr; } которая 1) форсирует вычисление каждого выражения, 2) вычисляет их принудительно последовательно, 3) возвращает значение последнего выражения, 4) пустой do {} это ошибка (ну это и правда нонсенс).

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

Опять, таки. Всё что я говорил про фигурные скобки к твоему if-expression не применимо, потому что я рассуждал в базисе if-statement и тернарного-if-выражения отдельно.

В жестком императивном си-подобном я бы хотел видеть такой if-statement:

if cond { // перевод строки обязателен. Почему скобки. Потому что там может быть несколько стейтментов.
st1
} [ else {
st2
} ]

В функциональном я бы хотел видеть такой if-expression:

name = expr1 if cond else expr2

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

Как теперь наложить сюда твоё блочное выражение. Наверное, вот так:

name = if cond then expr1 else expr2

но

if cond then {
action1;
action2;
}

То есть, переходить на стиль Go, когда результат if-выражения не используется.

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

T>> ну если хочешь, наверное, можно так сказать, я не пытался что-то прятать

T>>Просто, лично для очевидно, что большой if-else на одной строке хуже, чем на трёх.

ВВ>Вопрос не о стиле форматирования ("большой if-else"), а о грамматике if-else. Большой на одной строке хуже, маленький хуже на трех — это вопросы стиля. Грамматика может либо позволять записывать if-else в одну строку, либо не позволять.


T>>if not foo: continue # это единственный случай, где я сомневаюсь: ставить перевод строки или нет. И когда всё-таки поставлю тоже выглядит нормально.


ВВ>Потому что ты мыслишь в категориях "есть statements, есть expressions". А если это разделение убирается, то if — это всегда просто тернарный оператор. Всегда. Не более того. Иногда удобнее на нескольких строках, но часто хорошо выглядит и на одной.

ВВ>Вводить грамматику, согласно которой синтаксис некоторых expression заставляет писать их на разных строках, мне кажется плохой идеей.

Если это разделение убирается, то

expr1; // потеряли одно значение
if cond then expr2; // потеряли второе значение. Не знаем чему равен if, если cond false
cond3; // и вот это будет результатом блока

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

T>>Неправда твоя, Василий. Может быть, конечно, мы с разными пыхпыхами общались. Я от всех в один голос слышу одни и те же беды про индексацию функции, которая вернула массив, подгрузку нужных классов и пр. Стандартный набор баттхертов.


ВВ>От кого слышишь? От "рубироидников"? Ты же говорил, что у них все нормально


*С тем что нельзя передать метод, а не результат его вычисления* у них все нормально.

T>>От всех сишников, в один голос: рутина, рутина, нет неймспейсов, рутина, сегфолты, рутина. Действительно, на скобки никто не жалуется.


ВВ>Странно, я от сишников совсем другие вещи слышу. Впрочем, не суть. Считать решение в другом языке хорошим просто потому что им пользуется много людей — это какой-то неправильный подход. PHP пользуется много людей, как и джава-скриптом — вводим во все языки слабую типизацию?


Не потому что много людей пользуется, а потому что это не доставляет проблем. Много людей это всего-лишь подкрепление к аргументу. Насчёт слабой типизации у меня статистики нет, но я считаю, что это именно доставляет проблем.

T>>В Flow это лечится ленивостью.


ВВ>Ну т.е. функцию как значение передать все же можно?


Нет "функции как значения", потому что функция и результат её вычисления не разделены.

f = "Hello world"
print f

Ты можешь сказать, что в print передаётся функция. Ты можешь сказать, что в f передаётся результат вычисления функции. Ты будешь прав *в обоих* случаях.

T>>Я не выступаю с апологией конкретно этого подхода. Я говорю, что это разумный вариант. Один из многих других вариантов.


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


Если вызов функций это один конкретный случай, то так, да.
И если это не создаёт проблем, то вот она и разумность. Возможности урезаны, проблем нет, профит есть.

T>>Тип функции без параметров: type.

T>>type → void это отображение какого-то типа на одно значение void, то есть функция-константа, которая с любым аргументом возвращает одно значение.

ВВ>Вообще-то это нотация, через которую описывается функциональный тип в том же хаскеле. И тип функции без параметров не может быть просто type, в противном случае непонятно, как записывается тип для type.


Именно в той самой нотации я тебе и сказал. Если хочешь — попроси матёрых штангистов подтвердить или опровергнуть.

аргумент → аргумент → результат.

Что такое "тип для type"?

T>>Избавляемся от void, вводим ключевое слово для редкого случая — вызов нулларной функции.


ВВ>А чем мешает void? Его наличие необходимо как только снимается разница между expressions и statements. Или опять обратно statements прикручивать?


Ещё одна сущность.

T>>http://s.temoto.ru/flow/spec.rst

T>>Здесь есть очень старая версия. Там, может быть, всё ещё есть []. Но вроде бы должны быть примеры других конструкций типа bytes "foo".

ВВ>Жаль описания самого языка нет, так конечно сложновато понимать, о чем речь.


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

T>>Запомнить несложно. Сложно думать об этом, применять это, когда пишешь бизнес-логику, а не абстрактный код для примеров. Убрал второе выражение из двух в блоке и вроде бы можно убрать ';' вместе с ним. Чем думать об этом — проще всегда ставить ';' там где надо и там где можно без него.


ВВ>Аналогичная эвристика используется в Немерле. Согласно твоей же логике — много людей, на протяжении лет... — и так далее, и тому подобное.


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

ВВ>>>if → "if" expr expr "else" expr

T>>Терма/продукции expr expr всё ещё нет. Ты выделил *кусок* if.

ВВ>И что? Какая разница? Два expr идут друг за другом, разделенные пробелом. Что изменится, если их перенести в отдельную продукцию? Ничего. Это та самая ситуация, о которой я говорил — есть два expr, между ними только пробел. В си-подобном синтаксисе такая конструкция невозможна без конфликтов.


Ну какие конфликты-то? Приведи пример с разными разборами одной строки.
Re[25]: Про скобочки
От: Воронков Василий Россия  
Дата: 29.04.10 19:53
Оценка:
Здравствуйте, Temoto, Вы писали:

T>Согласно каким правилам "var x= 2" и "var x = 2" равнозначны, а "arr[index]" и "arr [index]" ­— нет?


Ну я у тебя спрашиваю. Они равнозначны или нет? Или же "var x= 2" и "var x = 2" — это разный код? И какой тогда правильный? В первом случае будет ошибка? Или что будет?

T>Ну я имел в виду, что парсеру/компилятору/неважно-чему понятно, что здесь ошибка: инфиксный минус к нечисловым аргументам. Конфликта, в смысле неоднозначности, — нет.


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

Push print
Push x
Min

И вот когда выполняется min, нам сделать некую проверку, определить, что print особого типа и начать выполнять совсем не тот код, который был сгенерирован компилятором. Ну т.е. это вообще практически нереальный сценарий.

T>Хакей, разделения нет. Тернарный оператор не нужен. Но if у тебя — выражение. Значит он и есть тернарный оператор. Кроме того, если if — всегда выражение, значит ты обязываешь всегда писать else (потому что иначе у ветки cond == false нет значения. Ну ладно, ты опять скажешь что значение будет вездессущий null, это мы уже обсуждали.


Вообще я сделал выводы из тех обсуждений "вездессущий null" отсутствует. Вместо него — void. А это подход, который проповедуется большинством функциональных языков, только там void часто называется unit. Блок else — обязательный.

T>Тогда then — самый читаемый и консистентный вариант, раз ты в такие рамки ставишь.


Эта мысль приходила мне в голову. Собственно, причина поднятия этой темы... Мне нравится код вида:

var x = if cond then y else z

if cond then
  y
else
  x


А вот так — уже не особо:

if cond then {
  ...
  y
}
else
  x


T>>>>>>>Я предлагал выделять *блоки стейтментов*. А в 'if-выражении', на мой взгляд, блоки не нужны, там можно ограничиться одним выражением в каждой позиции.

ВВ>>>>>>А если нужно несколько выражений внутри if?
T>>>>>Тогда это не выражение. Определи семантику выражения "несколько выражений" пожалуйста. Чему оно равно, как вычислять.

ВВ>>Для определения нескольких выражений используется специальное выражение "блок". Вот как он выглядит:


ВВ>>Блок может содержать от нуля до неограниченного кол-ва выражений. Блок сам по себе так же является выражением. Значением, которое возвращает блок, является значение последнего выражения внутри блока. Пустой блок возвращает void.


T>Хакей, блоки как в эрланге. Кстати я для Flow тоже думал о такой конструкции, типа do { expr; expr; } которая 1) форсирует вычисление каждого выражения, 2) вычисляет их принудительно последовательно, 3) возвращает значение последнего выражения, 4) пустой do {} это ошибка (ну это и правда нонсенс).


То, что ты описываешь — это скорее этакая do-нотация для энергичного вычисления выражений с побочными эффектами. Она имеет смысл при ленивости всего остального и чистоте языка. У меня блок это просто блок, он не гарантирует последовательности. Внутри него могут быть и ленивые выражения.

T>void вроде бы только для вызова нулларных функций был? Впрочем, это неважно.


Нет, не только. void — это то, что возвращают некоторые выражения. Например:

var x = for (...) ...


Значение x будет void.

T>Опять, таки. Всё что я говорил про фигурные скобки к твоему if-expression не применимо, потому что я рассуждал в базисе if-statement и тернарного-if-выражения отдельно.


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

T>В функциональном я бы хотел видеть такой if-expression:

T>name = expr1 if cond else expr2
T>Почему здесь скобок нет — потому что несколько быть не может, там одно везде выражение.

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

T>То есть, к твоему изначальному вопросу, ответ, наверное, будет такой: можно без проблем убрать всякие скобки из си-подобного синтаксиса. Убрать всякие скобки из конкретно твоего языка, с конкретно твоими прочими условиями без проблем не получится.


Видимо, это и есть "правильный ответ". Я и сам это в принципе уже понял.

T>Если это разделение убирается, то

T>expr1; // потеряли одно значение
T>if cond then expr2; // потеряли второе значение. Не знаем чему равен if, если cond false
T>cond3; // и вот это будет результатом блока
T>от такого кода у меня кипит мозг. Нафиг было всё делать выражениями, если этот факт будет редко использоваться.

Отчего же редко? Этот факт по-моему используется постоянно. Насколько я могу судить по аналогичным языка по крайней мере.
Ты просто в качестве примера взял нотацию для if из питона, которая лично мне не очень, честно говоря, и пытаешься на ее основе показать, как это плохо, когда все есть экспрешин.

T>>>Неправда твоя, Василий. Может быть, конечно, мы с разными пыхпыхами общались. Я от всех в один голос слышу одни и те же беды про индексацию функции, которая вернула массив, подгрузку нужных классов и пр. Стандартный набор баттхертов.


ВВ>>От кого слышишь? От "рубироидников"? Ты же говорил, что у них все нормально


T>*С тем что нельзя передать метод, а не результат его вычисления* у них все нормально.


T>>>От всех сишников, в один голос: рутина, рутина, нет неймспейсов, рутина, сегфолты, рутина. Действительно, на скобки никто не жалуется.


ВВ>>Странно, я от сишников совсем другие вещи слышу. Впрочем, не суть. Считать решение в другом языке хорошим просто потому что им пользуется много людей — это какой-то неправильный подход. PHP пользуется много людей, как и джава-скриптом — вводим во все языки слабую типизацию?


T>Не потому что много людей пользуется, а потому что это не доставляет проблем. Много людей это всего-лишь подкрепление к аргументу. Насчёт слабой типизации у меня статистики нет, но я считаю, что это именно доставляет проблем.


T>>>В Flow это лечится ленивостью.

ВВ>>Ну т.е. функцию как значение передать все же можно?
T>Нет "функции как значения", потому что функция и результат её вычисления не разделены.
T>f = "Hello world"
T>print f
T>Ты можешь сказать, что в print передаётся функция. Ты можешь сказать, что в f передаётся результат вычисления функции. Ты будешь прав *в обоих* случаях.

Ну это в случае функции без параметров. А как быть если функция принимает параметры? тут уже без разделения не обойдешься.

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

T>Если вызов функций это один конкретный случай, то так, да.
T>И если это не создаёт проблем, то вот она и разумность. Возможности урезаны, проблем нет, профит есть.

Ну у меня это создает просто катастрофические проблемы, весь язык построен на call by value.

T>Именно в той самой нотации я тебе и сказал. Если хочешь — попроси матёрых штангистов подтвердить или опровергнуть.

T>аргумент → аргумент → результат.
T>Что такое "тип для type"?

А что такое "просто type" для описания функционального типа?

T>>>Избавляемся от void, вводим ключевое слово для редкого случая — вызов нулларной функции.

ВВ>>А чем мешает void? Его наличие необходимо как только снимается разница между expressions и statements. Или опять обратно statements прикручивать?
T>Ещё одна сущность.

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

T>Да, косяк, я им не занимался давно. Увышка. В какой-то момент у меня было ощущение, что те недостатки хаскеля, которые я пытаюсь побороть — меньшее зло, чем громадная работа, которую предстоит сделать для реализации компилятора.


А можно пример таких недостатков?

ВВ>>И что? Какая разница? Два expr идут друг за другом, разделенные пробелом. Что изменится, если их перенести в отдельную продукцию? Ничего. Это та самая ситуация, о которой я говорил — есть два expr, между ними только пробел. В си-подобном синтаксисе такая конструкция невозможна без конфликтов.

T>Ну какие конфликты-то? Приведи пример с разными разборами одной строки.

Я же писал до этого, что если разделители между Expr — просто пробел, то при сохранении си-подобного синтаксиса будут конфликты. С теми же унарными операторами и проч.
Re[26]: Про скобочки
От: Temoto  
Дата: 29.04.10 21:01
Оценка:
T>>Согласно каким правилам "var x= 2" и "var x = 2" равнозначны, а "arr[index]" и "arr [index]" ­— нет?

ВВ>Ну я у тебя спрашиваю. Они равнозначны или нет? Или же "var x= 2" и "var x = 2" — это разный код? И какой тогда правильный? В первом случае будет ошибка? Или что будет?


Опять же, согласно каким правилам?

T>>Ну я имел в виду, что парсеру/компилятору/неважно-чему понятно, что здесь ошибка: инфиксный минус к нечисловым аргументам. Конфликта, в смысле неоднозначности, — нет.


ВВ>При динамической типизации будет понятно, что это "нечисловой аргумент" только в самый момент исполнения операции минус. Понимаешь? Вот у нас код стек-машины:


ВВ>Push print

ВВ>Push x
ВВ>Min

ВВ>И вот когда выполняется min, нам сделать некую проверку, определить, что print особого типа и начать выполнять совсем не тот код, который был сгенерирован компилятором. Ну т.е. это вообще практически нереальный сценарий.


Да, Min должен проверить типы аргументов и кинуть TypeError.

T>>Хакей, разделения нет. Тернарный оператор не нужен. Но if у тебя — выражение. Значит он и есть тернарный оператор. Кроме того, если if — всегда выражение, значит ты обязываешь всегда писать else (потому что иначе у ветки cond == false нет значения. Ну ладно, ты опять скажешь что значение будет вездессущий null, это мы уже обсуждали.


ВВ>Вообще я сделал выводы из тех обсуждений "вездессущий null" отсутствует. Вместо него — void. А это подход, который проповедуется большинством функциональных языков, только там void часто называется unit. Блок else — обязательный.


Не понял какие выводы. null переименовал в void?
И "большинство ф-х языков" это сколько/какие?

T>>Тогда then — самый читаемый и консистентный вариант, раз ты в такие рамки ставишь.


ВВ>Эта мысль приходила мне в голову. Собственно, причина поднятия этой темы... Мне нравится код вида:


ВВ>А вот так — уже не особо:


ВВ>
ВВ>if cond then {
ВВ>  ...
ВВ>  y
ВВ>}
ВВ>else
ВВ>  x
ВВ>


Да забей, всё нормально. Это цена скобок вместо отступов и ничего отдельно некрасивого в этом нет.

ВВ>>>Для определения нескольких выражений используется специальное выражение "блок". Вот как он выглядит:


ВВ>>>Блок может содержать от нуля до неограниченного кол-ва выражений. Блок сам по себе так же является выражением. Значением, которое возвращает блок, является значение последнего выражения внутри блока. Пустой блок возвращает void.


T>>Хакей, блоки как в эрланге. Кстати я для Flow тоже думал о такой конструкции, типа do { expr; expr; } которая 1) форсирует вычисление каждого выражения, 2) вычисляет их принудительно последовательно, 3) возвращает значение последнего выражения, 4) пустой do {} это ошибка (ну это и правда нонсенс).


ВВ>То, что ты описываешь — это скорее этакая do-нотация для энергичного вычисления выражений с побочными эффектами. Она имеет смысл при ленивости всего остального и чистоте языка. У меня блок это просто блок, он не гарантирует последовательности. Внутри него могут быть и ленивые выражения.


У тебя { expr1; expr2; expr3 } не гарантирует последовательности? Последовательность и ленивость ортогональны, кстати.

T>>В функциональном я бы хотел видеть такой if-expression:

T>>name = expr1 if cond else expr2
T>>Почему здесь скобок нет — потому что несколько быть не может, там одно везде выражение.

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


Круглых? Мусор.
Фигурных? Окружать одно выражение фигурными скобками — тоже мусор.
Почему одно выражение? Такая грамматика. Даже если там блок, это всё равно одно выражение ведь.

T>>Если это разделение убирается, то

T>>expr1; // потеряли одно значение
T>>if cond then expr2; // потеряли второе значение. Не знаем чему равен if, если cond false
T>>cond3; // и вот это будет результатом блока
T>>от такого кода у меня кипит мозг. Нафиг было всё делать выражениями, если этот факт будет редко использоваться.

ВВ>Отчего же редко? Этот факт по-моему используется постоянно. Насколько я могу судить по аналогичным языка по крайней мере.

ВВ>Ты просто в качестве примера взял нотацию для if из питона, которая лично мне не очень, честно говоря, и пытаешься на ее основе показать, как это плохо, когда все есть экспрешин.

(питона там не было)
Покажи любую функцию размером больше 150 символов из своей стандартной библиотеки.

T>>>>В Flow это лечится ленивостью.

ВВ>>>Ну т.е. функцию как значение передать все же можно?
T>>Нет "функции как значения", потому что функция и результат её вычисления не разделены.
T>>f = "Hello world"
T>>print f
T>>Ты можешь сказать, что в print передаётся функция. Ты можешь сказать, что в f передаётся результат вычисления функции. Ты будешь прав *в обоих* случаях.

ВВ>Ну это в случае функции без параметров. А как быть если функция принимает параметры? тут уже без разделения не обойдешься.


Т.е. нужно передать функцию, которая принимает аргумент?

f _ = "Hello world"
print f

Ты можешь сказать, что в print передаётся функция f, ты можешь сказать, что в print передаётся результат вычисления функции f. Ты будешь прав в обоих случаях.

Потому что результат вычисления функции f это нулларная функция, возвращающая "Hello world". Маниакальное каррирование даже там, где не просят. Это затрудняет создание функций с произвольным количеством аргументов. Я думал над этим и не придумал хорошего решения.

T>>Именно в той самой нотации я тебе и сказал. Если хочешь — попроси матёрых штангистов подтвердить или опровергнуть.

T>>аргумент → аргумент → результат.
T>>Что такое "тип для type"?

ВВ>А что такое "просто type" для описания функционального типа?


Я не понял вопроса. Но вот этот тип

x :: String

описывает функцию с именем "x" с 0 аргументов, которая возвращает строку.
Функциональным, обычно, называют тип a → b. Даже если b при этом сам является c → d. Оператор → правоассоциативен, как минус.

T>>>>Избавляемся от void, вводим ключевое слово для редкого случая — вызов нулларной функции.

ВВ>>>А чем мешает void? Его наличие необходимо как только снимается разница между expressions и statements. Или опять обратно statements прикручивать?
T>>Ещё одна сущность.

ВВ>Мне казалось, что тебе уж ее наличие должно показаться вполне логичным. Не говоря уж о том, что от разделения на expression и statements без нее не избавиться.


Если всё стало выражением, это значит только то, что ты теперь получил кучу гемора с определением какой же результат должен быть у всего.
Например, "for" ты потерял, потому что у него результата нет. Сказать на всё, что раньше было стейтментом, что у него результат — специальное значение void, это и есть создать именно лишнюю сущность, закрыть глаза на проблему выражений, создать костыль.

T>>Да, косяк, я им не занимался давно. Увышка. В какой-то момент у меня было ощущение, что те недостатки хаскеля, которые я пытаюсь побороть — меньшее зло, чем громадная работа, которую предстоит сделать для реализации компилятора.


ВВ>А можно пример таких недостатков?


— Эта идиотская идея, что типы документируют код. Это работает только в примитивных случаях, где и документировать нечего.
— Обязательная ленивость. Иногда всё-таки хочется взять на себя ответственность и указать порядок.
— Вся стандартная библиотека завязана на один конкретный тип последовательности: односвязанный список (который имеет конструктор ':'). Как следствие, для Array, Set, Map и пр. — свои, отдельные операции. Например, map/filter/fold работают *только с []*.
— Самая странная, убогая реализация туплов в мире. Это 64 строки типа http://google.com/codesearch/p?hl=en#5KTrgOW2hXs/pub/nslu2/sources/hugs98-Nov2003.tar.gz|cVG3t241wQU/hugs98-Nov2003/fptools/libraries/base/Data/Tuple.hs&q=%22%28,,%29%20a%20b%20c%22&l=71
— main имеет "грязный" тип IO. То есть на хаскеле нельзя писать чистые программы, только чистые функции.

Вот мнение матёрого штангиста на эту тему.
http://thesz.livejournal.com/1010226.html

ВВ>>>И что? Какая разница? Два expr идут друг за другом, разделенные пробелом. Что изменится, если их перенести в отдельную продукцию? Ничего. Это та самая ситуация, о которой я говорил — есть два expr, между ними только пробел. В си-подобном синтаксисе такая конструкция невозможна без конфликтов.

T>>Ну какие конфликты-то? Приведи пример с разными разборами одной строки.

ВВ>Я же писал до этого, что если разделители между Expr — просто пробел, то при сохранении си-подобного синтаксиса будут конфликты. С теми же унарными операторами и проч.


Понял теперь наконец-то.

if y -x else x

Да, тут засада.
Re[27]: Про скобочки
От: Воронков Василий Россия  
Дата: 29.04.10 21:21
Оценка:
Здравствуйте, Temoto, Вы писали:

T>>>Согласно каким правилам "var x= 2" и "var x = 2" равнозначны, а "arr[index]" и "arr [index]" ­— нет?

ВВ>>Ну я у тебя спрашиваю. Они равнозначны или нет? Или же "var x= 2" и "var x = 2" — это разный код? И какой тогда правильный? В первом случае будет ошибка? Или что будет?
T>Опять же, согласно каким правилам?

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

ВВ>>И вот когда выполняется min, нам сделать некую проверку, определить, что print особого типа и начать выполнять совсем не тот код, который был сгенерирован компилятором. Ну т.е. это вообще практически нереальный сценарий.

T>Да, Min должен проверить типы аргументов и кинуть TypeError.

Ты опять нить потерял. Речь была о том, чтобы суметь определить, что print — x это на самом деле не бинарная операция, а две операции: 1) вызов функции 3) negate x
TypeError и так будет.
А вот определить, что это две операции можно уже только при выполнении Min. Короче, это вообще какой-то бредовый вариант.

T>>>Хакей, разделения нет. Тернарный оператор не нужен. Но if у тебя — выражение. Значит он и есть тернарный оператор. Кроме того, если if — всегда выражение, значит ты обязываешь всегда писать else (потому что иначе у ветки cond == false нет значения. Ну ладно, ты опять скажешь что значение будет вездессущий null, это мы уже обсуждали.


ВВ>>Вообще я сделал выводы из тех обсуждений "вездессущий null" отсутствует. Вместо него — void. А это подход, который проповедуется большинством функциональных языков, только там void часто называется unit. Блок else — обязательный.


T>Не понял какие выводы. null переименовал в void?


null это не void

T>И "большинство ф-х языков" это сколько/какие?


Все языки семейства ML тебя устроят? Scala? Haskell? Nemerle?

ВВ>>То, что ты описываешь — это скорее этакая do-нотация для энергичного вычисления выражений с побочными эффектами. Она имеет смысл при ленивости всего остального и чистоте языка. У меня блок это просто блок, он не гарантирует последовательности. Внутри него могут быть и ленивые выражения.

T>У тебя { expr1; expr2; expr3 } не гарантирует последовательности? Последовательность и ленивость ортогональны, кстати.

Не гарантирует последовательности *исполнения*. Да, такой не гарантирует. Это тебе не монада.

T>(питона там не было)

T>Покажи любую функцию размером больше 150 символов из своей стандартной библиотеки.

А что ты конкретно хочешь увидеть? Стандартная библиотека еще не написана. Есть код для тестов.

T>f _ = "Hello world"

T>print f
T>Ты можешь сказать, что в print передаётся функция f, ты можешь сказать, что в print передаётся результат вычисления функции f. Ты будешь прав в обоих случаях.
T>Потому что результат вычисления функции f это нулларная функция, возвращающая "Hello world". Маниакальное каррирование даже там, где не просят. Это затрудняет создание функций с произвольным количеством аргументов. Я думал над этим и не придумал хорошего решения.

Ничего не понял. Как мне описать функцию, которая принимает один аргумент и совершает операцию над этим аргументом?

T>Я не понял вопроса. Но вот этот тип

T>x :: String
T>описывает функцию с именем "x" с 0 аргументов, которая возвращает строку.
T>Функциональным, обычно, называют тип a → b. Даже если b при этом сам является c → d. Оператор → правоассоциативен, как минус.

Опять ничего не понял. Функциональный тип у которого 0 аргументов?

T>Если всё стало выражением, это значит только то, что ты теперь получил кучу гемора с определением какой же результат должен быть у всего.

T>Например, "for" ты потерял, потому что у него результата нет. Сказать на всё, что раньше было стейтментом, что у него результат — специальное значение void, это и есть создать именно лишнюю сущность, закрыть глаза на проблему выражений, создать костыль.

Сохранение этого разделения представляет собой костыль куда больший. Оно в сущности означает, что для написания кода тебе по-прежнему придется использовать типичные конструкции императивного flow control — return и прочая.
К тому же я тут ровным счетом ничего не изобрел.
Re[27]: Про скобочки
От: Воронков Василий Россия  
Дата: 29.04.10 22:03
Оценка:
Здравствуйте, Temoto, Вы писали:

T>- Эта идиотская идея, что типы документируют код. Это работает только в примитивных случаях, где и документировать нечего.

T>- Обязательная ленивость. Иногда всё-таки хочется взять на себя ответственность и указать порядок.
T>- Вся стандартная библиотека завязана на один конкретный тип последовательности: односвязанный список (который имеет конструктор ':'). Как следствие, для Array, Set, Map и пр. — свои, отдельные операции. Например, map/filter/fold работают *только с []*.
T>- Самая странная, убогая реализация туплов в мире. Это 64 строки типа http://google.com/codesearch/p?hl=en#5KTrgOW2hXs/pub/nslu2/sources/hugs98-Nov2003.tar.gz|cVG3t241wQU/hugs98-Nov2003/fptools/libraries/base/Data/Tuple.hs&q=%22%28,,%29%20a%20b%20c%22&l=71
T>- main имеет "грязный" тип IO. То есть на хаскеле нельзя писать чистые программы, только чистые функции.

Кстати, а на чем ты собираешься все это писать? И во что компилировать?
Re[6]: Про скобочки
От: Gaperton http://gaperton.livejournal.com
Дата: 29.04.10 22:04
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Может, я не увидел в Гоу чего-то, что видишь ты? О какой идее речь? Сократить количество круглых скобочек?

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

Не, все правильно ты показываешь. Речь об идее избавления от круглых скобок. И не уродливо это — ты попиши примеры. Очень быстро привыкаешь, и начнет бесить обратно сишная традиция.

Можно избавиться и от фигурных скобок, введя двумерный синтаксис. Было бы желание.
Re[7]: Про скобочки
От: Воронков Василий Россия  
Дата: 29.04.10 22:14
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Не, все правильно ты показываешь. Речь об идее избавления от круглых скобок. И не уродливо это — ты попиши примеры. Очень быстро привыкаешь, и начнет бесить обратно сишная традиция.


В самом Go это не уродство, я такого не говорил. Это некрасиво в языке, где нет разделения на statement и expression — и, соответственно, все является expression. Поэтому любая конструкция, тот же if, может стоять справа от "=". И вот при таком подходе мне обязательные фигурные скобки кажутся странными.

А вообще синтаксис Go хорош тем, что из Сишного просто вытрясли весь мусор. Т.е. как не напишешь любую из конструкций Go, в ней не будет лишних токенов. Но сделано это ИМХО ценой неочевидности некоторых конструкций. Например, после if фигурные скобки обязательны, а после else — нет.

G>Можно избавиться и от фигурных скобок, введя двумерный синтаксис. Было бы желание.


Что такое двумерный синтаксис? Можно поподробнее?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.