Распакованные данные в штучной упаковке
Для поддержки параметрического полиморфизма и laziness , по умолчанию типы данных Haskell представлены единообразно в виде указателя на замыкание на кучу с такой структурой:
Это «коробочные» значения. распакованный объект представляется непосредственно самим значением, без какого-либо косвенного обращения или замыкания. Int
в штучной упаковке, но Int#
в штучной упаковке.
Ленивые значения требуют представление в штучной упаковке. Строгие значения этого не делают: они могут быть представлены либо как полностью оцененные замыкания в куче, либо как примитивные неупакованные структуры. Обратите внимание, что маркировка указателя - это оптимизация, которую мы можем использовать для объектов в штучной упаковке, чтобы закодировать конструктор в указателе на замыкание.
Отношение к строгости
Обычно распакованные значения генерируются специальным образом компиляторами функционального языка. Однако в Haskell распакованные значения являются особыми. Они:
- они имеют другой вид,
#
;
- можно использовать только в специальных местах; и
- они не подняты, поэтому не представлены в виде указателя на значение кучи.
Поскольку они не подняты, они обязательно строги. Представление лени невозможно.
Таким образом, определенные распакованные типы, такие как Int#
, Double#
, действительно представлены на компьютере как double или int (в обозначении C).
Анализ строгости
Отдельно GHC проводит анализ строгости обычных типов Haskell. Если установлено, что использование значения строгое, т. Е. Оно никогда не может быть «неопределенным», оптимизатор может заменить все виды использования обычного типа (например, Int
) на распакованный (Int#
), поскольку он знает, что использование Int
всегда строго, и поэтому замена на более эффективный (и всегда строгий) тип Int#
безопасна.
Конечно, у нас могут быть строгие типы без распакованных типов, например, полиморфный список со строгим элементом:
data List a = Empty | Cons !a (List a)
строг в своих элементах, но не представляет их как распакованные значения.
Это также указывает на ошибку, которую вы допустили в отношении строгих языков, , например, OCaml . Им по-прежнему необходимо поддерживать полиморфизм, поэтому они либо обеспечивают единообразное представление, либо специализируют типы данных и функции для каждого типа. GHC по умолчанию использует унифицированное представление, как и OCaml, хотя теперь GHC может специализировать типы и функции (например, шаблоны C ++).