Какова связь между распакованными типами и строгостью? - PullRequest
28 голосов
/ 28 июня 2010

Распакованные типы, такие как Int#, и строгие функции, такие как f (!x) = ..., - это что-то другое, но я вижу концептуальное сходство - они каким-то образом запрещают гнев / лень. Если бы Haskell был строгим языком, таким как Ocaml, каждая функция была бы строгой, а все типы были распакованы. Какова связь между распакованными типами и соблюдением строгости?

Ответы [ 3 ]

35 голосов
/ 28 июня 2010

Распакованные данные в штучной упаковке

Для поддержки параметрического полиморфизма и laziness , по умолчанию типы данных Haskell представлены единообразно в виде указателя на замыкание на кучу с такой структурой:

alt text

Это «коробочные» значения. распакованный объект представляется непосредственно самим значением, без какого-либо косвенного обращения или замыкания. Int в штучной упаковке, но Int# в штучной упаковке.

Ленивые значения требуют представление в штучной упаковке. Строгие значения этого не делают: они могут быть представлены либо как полностью оцененные замыкания в куче, либо как примитивные неупакованные структуры. Обратите внимание, что маркировка указателя - это оптимизация, которую мы можем использовать для объектов в штучной упаковке, чтобы закодировать конструктор в указателе на замыкание.

Отношение к строгости

Обычно распакованные значения генерируются специальным образом компиляторами функционального языка. Однако в Haskell распакованные значения являются особыми. Они:

  1. они имеют другой вид, #;
  2. можно использовать только в специальных местах; и
  3. они не подняты, поэтому не представлены в виде указателя на значение кучи.

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

Таким образом, определенные распакованные типы, такие как Int#, Double#, действительно представлены на компьютере как double или int (в обозначении C).

Анализ строгости

Отдельно GHC проводит анализ строгости обычных типов Haskell. Если установлено, что использование значения строгое, т. Е. Оно никогда не может быть «неопределенным», оптимизатор может заменить все виды использования обычного типа (например, Int) на распакованный (Int#), поскольку он знает, что использование Int всегда строго, и поэтому замена на более эффективный (и всегда строгий) тип Int# безопасна.

Конечно, у нас могут быть строгие типы без распакованных типов, например, полиморфный список со строгим элементом:

data List a = Empty | Cons !a (List a)

строг в своих элементах, но не представляет их как распакованные значения.

Это также указывает на ошибку, которую вы допустили в отношении строгих языков, , например, OCaml . Им по-прежнему необходимо поддерживать полиморфизм, поэтому они либо обеспечивают единообразное представление, либо специализируют типы данных и функции для каждого типа. GHC по умолчанию использует унифицированное представление, как и OCaml, хотя теперь GHC может специализировать типы и функции (например, шаблоны C ++).

16 голосов
/ 28 июня 2010

Распакованные типы обязательно являются строгими, но не все строгие значения обязательно распаковываются.

data Foo a = Foo !a !a

имеет два строгих поля

data Bar a = Bar {-# UNPACK #-} !Int !a

имеет два строгих поля, но первое -unboxed.

В конечном счете, причина в том, что распакованные типы являются (обязательно) строгими, заключается в том, что нет места для хранения thunk, поскольку они просто плоские, тупые данные в этой точке.

8 голосов
/ 28 июня 2010

Аргументы любых типов могут быть сделаны "строгими", но единственными распакованными типами, которые имеют соответствующие типы в штучной упаковке, являются Char#, Int#, Word#, Double# и Float#.

Если вы знаете языки низкого уровня, такие как C, это легче объяснить. Распакованные типы имеют тип int, double и т. Д., А упакованные типы имеют вид int*, double* и т. Д. Когда вы получили int, вы уже знаете все значение в том виде, как оно представлено в битовой структуре, следовательно, это не ленивый. Он также должен быть строгим, поскольку все значения int действительны, а не & perp;.

Однако, учитывая int*, вы можете выбрать разыменование указателя позже, чтобы получить фактическое значение (таким образом, ленивое), и возможно иметь недопустимые указатели (они содержат & perp; т.е. не строгие).

...