95

通读这篇经典论文,我陷入了自相矛盾。不幸的是,该部分很薄,维基百科页面什么也没说。

我的 Haskell 翻译是:

para :: (a -> [a] -> b -> b) -> b -> [a] -> b
para f base = h
  where
    h []       =   base
    h (x:xs)   =   f x xs (h xs)

但我不明白——我对类型签名或期望的结果没有任何直觉。

什么是变形,有哪些有用的例子?


是的,我已经看到了这些 问题,但它们没有直接涉及超态,并且只指出可能作为参考有用的资源,但不能作为学习材料。

4

1 回答 1

112

是的,就是这样para。与 catamorphism 比较,或foldr

para  :: (a -> [a] -> b -> b) -> b -> [a] -> b
foldr :: (a ->        b -> b) -> b -> [a] -> b

para  c n (x : xs) = c x xs (para c n xs)
foldr c n (x : xs) = c x    (foldr c n xs)
para  c n []       = n
foldr c n []       = n

有些人将超态称为“原始递归”,而变态 ( foldr) 称为“迭代”。

其中foldr's 的两个参数为输入数据的每个递归子对象(这里是列表的尾部)给出一个递归计算的值,para's 的参数获取原始子对象和从中递归计算的值。

一个很好地表达的示例函数para是列表的适当满足的集合。

suff :: [x] -> [[x]]
suff = para (\ x xs suffxs -> xs : suffxs) []

以便

suff "suffix" = ["uffix", "ffix", "fix", "ix", "x", ""]

可能更简单的仍然是

safeTail :: [x] -> Maybe [x]
safeTail = para (\ _ xs _ -> Just xs) Nothing

其中“cons”分支忽略其递归计算的参数,只返回尾部。懒惰地评估,递归计算永远不会发生,并且在恒定时间内提取尾部。

您可以很容易地定义foldrusing ;定义frompara有点棘手,但它肯定是可能的,每个人都应该知道它是如何完成的!parafoldr

foldr c n =       para  (\ x  xs  t ->           c x    t)       n
para  c n = snd . foldr (\ x (xs, t) -> (x : xs, c x xs t)) ([], n)

para定义with的技巧foldr是重建原始数据的副本,以便我们在每一步都可以访问尾部的副本,即使我们无法访问原始数据。最后,snd丢弃输入的副本,只给出输出值。它不是很有效,但如果你对纯粹的表现力感兴趣,para给你的不超过foldr. 如果你使用这个foldr-encoded 版本para,那么safeTail毕竟将花费线性时间,逐个元素地复制尾部元素。

所以,就是这样:这para是一个更方便的版本,foldr它使您可以立即访问列表的尾部以及从中计算出的值。

在一般情况下,使用作为仿函数的递归固定点生成的数据类型

data Fix f = In (f (Fix f))

你有

cata :: Functor f => (f         t  -> t) -> Fix f -> t
para :: Functor f => (f (Fix f, t) -> t) -> Fix f -> t

cata phi (In ff) = phi (fmap (cata phi) ff)
para psi (In ff) = psi (fmap keepCopy   ff) where
  keepCopy x = (x, para psi x)

再一次,这两者是相互定义的,paracata相同的“复制”技巧定义

para psi = snd . cata (\ fxt -> (In (fmap fst fxt), psi fxt))

同样,para并不比 更具表现力cata,但如果您需要轻松访问输入的子结构,则更方便。

编辑:我记得另一个很好的例子。

考虑由Fix TreeFwhere给出的二叉搜索树

data TreeF sub = Leaf | Node sub Integer sub

并尝试为二叉搜索树定义插入,首先是 a cata,然后是 a para。您会发现该para版本要容易得多,因为您需要在每个节点处插入一个子树,但保留另一个子树。

于 2012-11-09T23:34:22.483 回答