Предмет обсуждения - язык OCaml.
Собеседник:
Всегда удивляло желание людей делать языки с гавно-синтаксисом, которые адово читать. И это при том что с точки зрения выполнения кода, нет никакой разницы относительно синтаксиса(главное что бы не было избыточных проходов парсера)
Но люди упорно стараются что бы другие страдали. Зачем?Evaluation of these expressions involves an environment that maps identifiers to values, represented as a list of pairs.
# let rec eval env = function | Num i -> i | Var x -> List.assoc x env | Let (x, e1, in_e2) -> let val_x = eval env e1 in eval ((x, val_x) :: env) in_e2 | Binop (op, e1, e2) -> let v1 = eval env e1 in let v2 = eval env e2 in eval_op op v1 v2 and eval_op op v1 v2 = match op with | "+" -> v1 + v2 | "-" -> v1 - v2 | "*" -> v1 * v2 | "/" -> v1 / v2 | _ -> failwith ("Unknown operator: " ^ op);; val eval : (string * int) list -> expression -> int = <fun> val eval_op : string -> int -> int -> int = <fun>
Дык, энто же паттерн матчинг. За ним куча complexity спрятана 🙂
Что мне не нравится из того, что используется в этом куске кода, это, например, то, что для определения функции с паттерн матчингом используется слово function, а для "обычной" функции - нет.
Ещё не нравится, что and используется в выражении, чтоб доопределить ещё функцию eval_op (я так понял этот код) - но это скорей вопрос к автору кода, а не к автору языка.
Но в целом это довольно "скороспелые" претензии, не прочувствовав язык как нечто целостное, я бы их всерьёз не предъявлял 🙂
ок давай разберем
определение функции бинарным OR "|" при этом в коде чуть ниже после энд оператор уже вроде как обычный OR используется.
что вообще должно означать Num i -> i ? Почему не просто Num i?
у нас в обозначении функции env в ее коде env. Очень надеюсь что это рекурсия то нихрена не уверн.
val_x = а дальше хер пойми что. Ну и фраза снизу Let x=1 in x+x. Мне как математику от такого обозначения хочеться выйти в окно.. бо вообще хер пойми что это выражение значит.
конкатанация строк через знак возведения в степень.. ну тоже сильно. Особенно будет сильно когда в коде две строки а и б и код a^b ))
Чем больше различие в языке от стандартных норм.. тем больше проблем это создает при переходе.
А херова туча закарлючек и отсутсвие скобок в нужных местах делает это повестью минувших лет особенно в мат операциях. и большем обьеме саб вызовов
- Это не бинарный OR, это паттерн матчинг - вся вот эта конструкция
| ... -> ...
| ... -> ...
...
| -> ...
Это как бы расширенный switch
, который распознаёт не просто списки или диапазоны целых, но более сложные структуры, например,
-
Тут скорее всего case-классы. Это у нас код чего? Эвалюейшена некого выражения. Предполагаю, выражения на окамле же.
Num
,Var
,Let
,Binop
- это Case-классы, разновидности составляющей распаршенного выражения.
Соответственно если у нас паттерн такой,Num i
, это значит, что сматчится кейс-классNum
, при этом в качестве его параметра стоитi
- символ, значит, сматчитсяNum
с любым параметром, аi
забиндится на конкретное значение, соответственно результатом всего паттерн-матчинг-выражения будет то что после->
, т.е.i
. -
env
это параметр функцииeval
, ну и да, там есть рекурсия -
Let ( x, e1, in_e2) ->
... заматчили кейс-классLet
, забиндили его параметры (или, если хочешь, поля) в соответствующие переменные.
Выражение такого типа - по аналогии с другими функциональными языками -let x = ... in ...
- это значит вычислитьx
и подставить его в выражение послеin
. В императивном языке это бы было сделано просто двумя последовательными присвоениями. Но с такой конструкцией транслятору языка ясно, что для чего нужно вычислить, что позволяет легче делать ленивые вычисления.eval ((x, val_x) :: env) in_e2
- сконкатенировать пару(x, val_x)
к спискуenv
и вызватьeval
с двумя параметрами - вот этот список иin_e2
.
По поводу стандартных вещей в синтаксисе - это дело привычки, традиции (и всегда холивары по этому поводу случаются - фигурные скобки, отступы или вообще begin
..end
?). Ну и стоит вспомнить, что семейство языков-то древнее, и не факт тогда был, что алголоподобные стали бы рулить. Так что это просто другая традиция, другое ответвление. Это как ругать китайский язык за непривычную нам, европейцам, систему письменности 🙂
Таки да, там кейс-класс, выше определен:
# type expression =
| Num of int
| Var of string
| Let of string * expression * expression
| Binop of string * expression * expression;;
Comments (21)
let rec
это взаимно рекурсивное определение двух функций сразу, зависящих друг от друга:eval
иeval_op
- отсюда и кривоватый синтаксис с andАвтор кода, конечно, прогнал с function, решив обойтись без названия второго аргумента. Можно было бы написать попроще
Сперва не совсем понял, почему им понадобилось вообще описывать функции как рекурсивные эксплицитно - вот почему.
Это какая-то фишка из древних времён, нерекурсивность позволяет некоторые оптимизации. Оригинальный фортран не разрешает рекурсию, и это даёт возможность статической аллокации локальных переменных, можно совсем без стека обойтись.
Ну отсутствие рекурсивности-то и вычислить можно, тупо проверив наличие где-то в выражении вызова себя. И оптимизировать хвостовую рекурсию языки в целом могут, распознав её.
Проблема возникает, когда у нас уже есть в неймспейсе такое же имя. В окамле можно переопределять имя. Как я понимаю, такой код будет работать (и это вложенный
let
, а не императивная последовательность операций с побочным эффектом):Странноватый стиль, однако, но зачем-то авторам ML такое понадобилось.
Тогда упоминание этого имени в теле функции - это ссылка на старую функцию или на вновь определяемую?
В таком варианте - ссылка на старую:
А в таком - на самоё себя:
В целом не очень понимаю, зачем было позволять переопределять переменную (где-либо, кроме как в интерактивном интерпретаторе).
Shmuel Leib Melamud В предыдущем комменте нажатие на "Read more..." для разворачивания коммента то ли тормозит, то ли срабатывает не с первого раза.
Update: Вообще не работает, работает клик по телу коммента.
Например, для дебага:
Shmuel Leib Melamud комменты с телефона не получают кастомной аватарки, а с компа получают
Сейчас проверим.
Я вижу кастомную аватарку в обоих случаях.
Да, об этом я уже знаю.
А, это та же фишка, на которую я наткнулся ранее?
P.S.: Если у человека одна-единственная аватарка, контрол для выбора аватарок можно не показывать. Хотя, с другой стороны, это напоминает ему, что их у него может быть больше одной.
Да, я именно для этого и оставил - чтобы напоминать, что может быть больше одной аватарки.
Но я таки вижу, что в первых комментах аватарки нет. Какая версия клиента на телефоне? (Открыть меню уведомлений, там в самом низу бледными буквами написана версия.)
Я не знаю, что такое меню уведомлений, там ничего не написано - у меня тонкий клиент вокруг web.moera.org , причём нотификации иногда открываются в браузере, а не в клиенте. Похоже, клиент тыщу лет не обновлялся.
App info
Version: 0.10.0.0
Released on Jan 4, 2021
Нет, это не та версия. Меню уведомлений - это то, что открывается, если нажать на колокольчик.
9f9a357
Да, старая версия.
Сорри, я сейчас пишу новый клиент для Android, в котором этих проблем с обновлением клиента не будет. Потерпите еще недели две 😞
А починить руками можно? Какой-нибудь кэш сбросить
Да, можно сбросить в Chrome все данные, связанные с
web.moera.org
. После этого придется логиниться заново, но клиент должен обновиться. Актуальная версия сейчас:289b12e+df18
.