(no subject)

Jan 15, 2019 20:47

Не только лишь все знают, что в Ocaml'е параметры функций
вычисляются немножко по-арабски - справа налево. И это суровая
оптимизационная необходимость, описанная в книге Ксавье Леруа
"The ZINC experiment: an economical implementation of the ML language",
которую можно скачать у него на сайте https://xavierleroy.org/bibrefs/Leroy-ZINC.html,
(страница 14).

То есть, если мы загрузим REPL и напишем

(fun _ _ -> ()) (print_string "Left") (print_string "Right")

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

Теперь вспомним, что в ML в 80-х происходил переход от кортежей
к каррированным функциям. То есть, вместо f (x, y) люди начали писать
f x y (в библиотеке SML Basis ещё остались следы древних времён).
То есть, немного предсказуемо, из

(fun _ -> ()) (print_string "Left", print_string "Right")

мы получаем опять "RightLeft". Вроде бы так и должно быть - каррированная
функция f x y могла быть записана программистом как f(x,y), а значит оба
варианта должны иметь одинаковые побочные эффекты, чтобы сюрпризов было
по-меньше.

Тем не менее, (x,y) - это кортеж. Соответственно, порядок инициализации полей
кортежа (a, b, c, d) - справа налево. Для проверки

(print_string "Left", print_string "Middle", print_string "Right")

в REPL действительно даёт "RightMiddleLeft".

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

[ print_string "Left"; print_string "Middle"; print_string "Right"]

и

[| print_string "Left"; print_string "Middle"; print_string "Right"|]

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

type r = { a : unit; b : unit; c : unit }
let _ = { a = print_string "Left"; b = print_string "Middle"; c = print_string "Right" }

И, что самое поразительное, точно также работают и функторы - программа

module type S = sig val x : unit end

module F : functor (X : S) (Y : S) -> struct end

module C = F (struct let x = print_string "Left" end)
(struct let x = print_string "Right" end)

выводит "RightLeft". С объектами дела обстоят точно также - new obj a b вычислит сперва b, затем a.

И вроде бы всё безумно одинаково, последовательно, скучно и совершенно нехарактерно
для эклектичного Ocaml, но идиллию портят

(print_string "Left"; print_string "Middle"; print_string "Right")

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

{|print_string "Left"; print_string "Middle"; print_string "Right"|}

которое вообще строка. И, всё-таки, это Ocaml!
Previous post Next post
Up