unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
文档中给出的示例:
unfoldr (\b -> if b == 0 then Nothing else Just (b, b-1)) 10
可以使用冗余对轻松编写:
unfoldr (\b -> if b == 1 then Nothing else Just (b-1, b-1)) 11
unfoldr
对(a,b)
对需要什么?为什么它的类型不是(a -> Maybe a) -> a -> [a]
?
答案 0 :(得分:12)
类型为
的函数(a -> Maybe a) -> a -> [a]
将输出列表元素类型限制为与生成过程中的线程相同的状态。 unfoldr
更通用,因为它允许使用独立类型的状态。
答案 1 :(得分:4)
利用一些理论,人们可以恢复递归类型的折叠/展开类型,包括列表,理解它们的原因。
让A
成为固定类型。类型“A
s的列表”满足同构
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)
为了处理类型上的固定点,我们需要从posets切换到类别,这使得一切都更复杂。非常非常粗略地说,每个<=
都被一些态射取代。例如,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派生于coinduction原则,它处理最大的后缀点T
(成为代数)
(U <= F(U)) ==> (U <= T)