すべての 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 のデータ型が共導的であるためであり、遅延評価モデルに対する批判の的となっています。これらの問題は、厳密な合計と積 (および値関数による呼び出し) のみを使用し、特別な "Lazy" データ コンストラクターを追加することで回避できます。
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
そして、すべての同型を忠実に符号化できます。