Давайте возьмем наивную реализацию fix
:
fix f = f (fix f)
Для функции f
это создает что-то вроде следующего:
f (f (f (f (f (f (f ...
Fix
newtype делает то же самое, но для типов. Поэтому, если мы возьмем тип Maybe
, мы захотим создать:
Maybe (Maybe (Maybe (Maybe (Maybe (Maybe ...
Как бы мы создали функцию, которая создает этот тип? Сначала мы можем попробовать с синонимом типа:
-- fix f = f (fix f)
type Fix f = f (Fix f)
Вы должны увидеть, что это то же самое, что и наивная реализация fix
выше с некоторыми незначительными изменениями. Но это недопустимо Haskell!
Это происходит по ряду причин: в основном, Haskell не допускает бесконечных типов, как пример Maybe
, а система типов Haskell строгий, в отличие от ленивых оценок, требуемых в fix
. Вот почему нам нужен newtype
. Новые определения типов (введенные с newtype
или data
) допускают рекурсию, поэтому мы берем наш синоним типа и меняем его на новый тип.
type Fix f = f (Fix f)
newtype Fix f = f (Fix f) -- change to newtype
newtype Fix f = Fix (f (Fix f)) -- need to have a constructor
newtype Fix f = Fix { unFix :: f (Fix f) } -- And name the field, also