利用一些理论,可以恢复递归类型的折叠/展开类型,包括列表,了解它们为何如此。
设A 为固定类型。 “As的列表”类型满足同构
List ~~ Either () (A, List)
可以读作“列表值是一个特殊值(空列表),或者是 A 类型的值,后跟一个列表值”。
用更简洁的表示法,我们可以将Either 写成中缀+:
List ~~ () + (A, List)
现在,如果我们让F b = () + (A, b),我们就有了
List ~~ F List
上面是一个不动点方程,在使用递归类型时总是会出现。对于T ~~ F T 定义的任何递归类型,我们可以
导出相关折叠/展开的类型(也称为cata/ana 或归纳/共归纳原理)
fold :: (F b -> b) -> T -> b
unfold :: (b -> F b) -> b -> T
在列表的情况下,我们得到
fold :: ((() + (A, b)) -> b) -> List -> b
unfoldr :: (b -> (() + (A, b))) -> b -> List
也可以重写展开,注意到Maybe c ~~ () + c:
unfoldr :: (b -> Maybe (A, b)) -> b -> List
折叠可以改用
((x + y) -> z) ~~ (x -> z, y -> z)
得到
foldr :: (() -> b, (A, b) -> b) -> List -> b
那么,由于() -> b ~~ b,
foldr :: (b, (A, b) -> b) -> List -> b
最后,自从(x, y) -> z ~~ x -> y -> z(currying),我们有了
foldr :: b -> ((A, b) -> b) -> List -> b
又一次:
foldr :: b -> (A -> b -> b) -> List -> b
最后一次翻转x -> y -> z ~~ y -> x -> z:
foldr :: (A -> b -> b) -> b -> List -> b
这些类型如何遵循(共)归纳原则?
域理论指出,最少不动点 (F(T)=T) 与最少
前缀点 (F(T)<=T),当 F 在某个特定偏序上是单调的。
归纳原理简单说明,如果T是最小前缀点,F(U)<=U,那么T<=U。 (证明。这是最少!。QED。)
在公式中,
(F(U) <= U) ==> (T <= U)
为了处理类型上的固定点,我们需要从姿势转换到类别,这使得一切都变得更加复杂。非常非常粗略地,每个<= 都被一些态射替换。例如,F(U)<=U 现在意味着存在一些态射F U -> U。 “单调F”意味着F是一个函子(因为a<=b暗示F(a)<=F(b)现在变成(a->b)暗示F a -> F b)。前缀点是 F 代数 (F u -> u)。 “最小”变成“初始”。以此类推。
因此折叠的类型:(暗示也是->)
fold :: (F u -> u) -> (T -> u)
Unfold 源自共归纳原理,它处理最大后缀点 T(变成余代数)
(U <= F(U)) ==> (U <= T)