Когда в OCaml создаются физически разные значения?
Я пытаюсь понять, что такое операторы физического равенства (Pervasives.(==)
а также Pervasives.(!=)
) значит в OCaml.
Руководство по языку говорит, что выражение ""
является "константой", а не "выражением":
6.5 Константы
константа::== ... строковый литерал
но я не могу найти никаких слов, указывающих, что константы по отдельности / предварительно оценены или объединены, а REPL указывает, что изменяемые строковые значения (к счастью) не объединяются.
(* a *) "" == "";; (* false *)
(* b *) "foo" == "foo";; (* false *)
(* c *) "" == String.copy "";; (* false *)
(* d *) () == ();; (* true *)
(* e *) (42, -42) == (42, -42);; (* false *)
(* f *) ("", 1) == ("", 1);; (* false *)
(* g *) None == None;; (* true *)
(* h *) (Some None) == (Some None);; (* false *)
Раздел " 19.3 Представление типов данных OCaml" предполагает, что спецификация языка требует, чтобы bools, ints, char, значение единицы измерения, простые варианты и пустые списки были самоотверженными.
Должна ли реализация вести себя так, как описано выше, чтобы быть соответствующей реализацией OCaml?
Может ли соответствующая реализация OCaml переписать указатель на b
указать на a
когда a = b (* structurally *)
верно, и оба являются значениями неизменяемого типа (или эффективно неизменяемыми значениями, такими как строки / массивы нулевой длины), как это иногда делается для уменьшения числа достижимых младших значений в поколенческом ГХ?
2 ответа
Когда я читаю спецификацию языка, очень мало гарантий, когда значения различны. Я полагаю, что единственная гарантия находится в документации модуля Pervasives:
На изменяемых типах, таких как ссылки, массивы, строки, записи с изменяемыми полями и объекты с переменными изменяемого экземпляра, e1 == e2 имеет значение true, если и только если физическая модификация e1 также влияет на e2. На не изменяемых типах поведение ( ==) зависит от реализации; однако гарантируется, что e1 == e2 подразумевает сравнение e1 e2 = 0.
Одна из замечательных особенностей FP - это то, что компилятор и среда выполнения могут делать произвольно умные вещи с неизменяемыми значениями. Так что эта гарантия - это все, что вы действительно хотели бы иметь (ИМХО).
В общем, да, среда выполнения или компилятор свободны (опять же, ИМХО), чтобы делиться (а не делиться) неизменяемыми значениями любым способом, который, по его мнению, будет полезен.
Я бы не стал интерпретировать секцию представления как часть спецификации языка. Это просто полезная документация текущей реализации.
Просто замечание: строковые константы объединяются не так, как вы тестируете:
let f () = "foo"
let b = f () == f () (* true *)
Это действительно может привести к ошибкам, если вы измените вывод f ()
звонок: это повлияет на все дальнейшие звонки. Консенсус в отношении этого поведения заключается в том, что изменяемая строка является исторической ошибкой (необходимо иметь тип изменяемого буфера, отличный от основного типа строки, для которого выбор кодирования и сложность конкатенации должны быть более важными) и что пул, нарушающий семантику, достаточно интересен по производительности можно допустить, что строковые константы не являются мутированными. Если кто-то хочет избежать объединения, нужно просто позвонить String.copy
непосредственно на строковую константу.