(这更像是一个评论而不是一个答案,但我需要更多的空间。)
类型a -> b
对应a <= b
。这很有用,例如,在类型级别谈论固定点,这是正确定义递归类型(列表、树等)所必需的。
回想一下递归是如何解决的,没有类别。在域论中,给定一个函数,f :: a -> a
我们寻找一个最不x
令人满意的f x = x
(最不固定点)。事实证明,这也是最不x
令人满意的f x <= x
(最少前缀点)。然后我们得到归纳原理
f y <= y ==> fix f <= y
这基本上表明,如果我们有任何前缀点y
,那么最小(预先)固定点fix f
必须小于y
- 实际上,它是最小的!
现在,让我们在上面撒一些类别粉末。蕴涵变成了->
箭头,<=
也变成了->
。我们得到
(f y -> y) -> fix f -> y
似曾相识,我在哪里看到的……?啊!
newtype Fix f = Fix { unFix :: f (Fix f) }
cata :: Functor f => (f y -> y) -> Fix f -> y
cata g = g . fmap (cata g) . unFix
因此,cata
一般消除器/变态只是旧归纳原理的类别授权版本。
请注意域点y
现在如何成为我们类别中的对象(即类型)。此外,函数f
必须适用于y
,因此这些不是我们类别中的态射(可能是函数值 :: A -> B
,从某种类型到某种类型),而是对应于类型类别中的函子(将类型映射到类型:: * -> *
)。