所有的 ADT与(,)
, Either
, ()
,(->)
的某种组合是同构的(几乎——见结尾)Void
Mu
data Void --using empty data decls or
newtype Void = Void Void
并Mu
计算仿函数的不动点
newtype Mu f = Mu (f (Mu f))
所以例如
data [a] = [] | (a:[a])
是相同的
data [a] = Mu (ListF a)
data ListF a f = End | Pair a f
它本身同构于
newtype ListF a f = ListF (Either () (a,f))
自从
data Maybe a = Nothing | Just a
同构于
newtype Maybe a = Maybe (Either () a)
你有
newtype ListF a f = ListF (Maybe (a,f))
可以在 mu 中内联到
data List a = List (Maybe (a,List a))
和你的定义
data List a = List a (Maybe (List a))
只是 Mu 的展开和外部 Maybe 的消除(对应非空列表)
你完成了......
几件事
使用自定义 ADT 可提高清晰度和类型安全性
这种普遍性很有用:参见 GHC.Generic
好吧,我说几乎是同构的。不完全是,即
hmm = List (Just undefined)
[a] = [] | (a:[a])
在列表的定义中没有等效值。这是因为 Haskell 数据类型是协约的,并且一直是惰性求值模型的一个批评点。您可以通过仅使用严格的求和和乘积(以及按值函数调用)并添加特殊的“惰性”数据构造函数来解决这些问题
data SPair a b = SPair !a !b
data SEither a b = SLeft !a | SRight !b
data Lazy a = Lazy a --Note, this has no obvious encoding in Pure CBV languages,
--although Laza a = (() -> a) is semantically correct,
--it is strictly less efficient than Haskell's CB-Need
然后可以忠实地编码所有同构。