Ответ 1
Unboxed vs Boxed Datastrong >
Чтобы поддерживать параметрический полиморфизм и лень, по умолчанию типы данных Haskell представлены равномерно как указатель на closure на куча, со структурой вроде этого:
Это значения "в штучной упаковке". Объект unboxed представляется непосредственно самим значением без каких-либо косвенных ограничений или закрытия. Int
помещается в коробку, но Int#
распаковывается.
Ленивые значения требуют представления в штучной упаковке. Строгие значения не имеют: они могут быть представлены либо как полностью оцененные замыкания в куче, либо как примитивные распакованные структуры. Обратите внимание, что указатель тегирования - это оптимизация, которую мы можем использовать на бокс-объектах, чтобы закодировать конструктор в указателе на закрытие.
Отношение к строгости
Обычно незанятые значения генерируются специальным образом компиляторами функционального языка. В Haskell, однако, unboxed values являются специальными. Они:
- у них другой тип,
#
; - может использоваться только в особых местах; и
- они не используются, поэтому они не представлены как указатель на значение кучи.
Потому что они небрежные, они обязательно строги. Представление лень невозможно.
Таким образом, отдельные типы unboxed, такие как Int#
, Double#
, на самом деле представлены как двойные или int на машине (в обозначении C).
Анализ строгости
Отдельно GHC делает анализ строгости обычных типов Haskell. Если значение используется как строковое, т.е. Оно никогда не может быть "undefined" - оптимизатор может заменить все виды использования обычного типа (например, Int
) на unboxed (Int#
), поскольку он знает что использование Int
всегда строгое, и поэтому замена более эффективным (и всегда строгим) типом Int#
безопасна.
Конечно, мы можем иметь строгие типы без распакованных типов, например, строковый полиморфный список:
data List a = Empty | Cons !a (List a)
является строгим в своих элементах, но не представляет их как незанятые значения.
Это также указывает на ошибку, которую вы сделали о строгих языках, как OCaml. Им по-прежнему необходимо поддерживать полиморфизм, поэтому либо они обеспечивают единообразное представление, либо специализируют типы данных и функции для каждого типа. GHC по умолчанию использует равномерное представление, равно как и OCaml, хотя GHC также может теперь специализировать типы и функции (например, шаблоны С++).