Haskell 本原递归和反同构之间有什么联系?

Haskell 本原递归和反同构之间有什么联系?,haskell,recursion,functional-programming,fold,catamorphism,Haskell,Recursion,Functional Programming,Fold,Catamorphism,使用以下自然数的亚同态,我可以实现各种算术算法,而不必处理递归: cataNat :: b -> (b -> b) -> Natural -> b cataNat zero succ = go where go n = if (n <= 0) then zero else succ (go (n - 1)) fib :: Natural -> Natural fib = fst . cataNat (0, 1) (\(a, b) -> (b

使用以下自然数的亚同态,我可以实现各种算术算法,而不必处理递归:

cataNat :: b -> (b -> b) -> Natural -> b
cataNat zero succ = go
  where
    go n = if (n <= 0) then zero else succ (go (n - 1))

fib :: Natural -> Natural
fib = fst . cataNat (0, 1) (\(a, b) -> (b, a + b))
cataNat::b->(b->b)->Natural->b
cataNat zero成功=成功
哪里
go n=如果(n自然)
fib=fst.cataNat(0,1)(\(a,b)->(b,a+b))

cataNat
在我看来类似于原始递归。至少它的每个应用程序似乎都被终止,无论提供了
zero
succ
的哪种组合。在每次迭代中,整个问题都由最小/最简单的问题实例分解。因此,即使它在技术上不是原始的原语递归似乎具有同样的表达能力。如果这是真的,则意味着一个反同构不足以表达一般的递归。我们可能需要一个hylomorphism来实现这一点。我的推理正确吗,也就是说,等价性是否适用于任何类型的反同构,而不仅仅适用于自然数?

原语递归对应它直接指向一个准态

你是对的,一个反同态与一个准同态具有同等的理论能力,但它们在操作方面可能在重要方面有所不同。例如,让我们转到列表而不是NAT

cata :: b -> (a -> b -> b) -> [a] -> b
cata = flip foldr -- I'm lazy, but this argument order makes a bit more sense for this example

para :: b -> (a -> [a] -> b -> b) -> [a] -> b
para z _ []     = z
para z f (x:xs) = f x xs (para z f xs)

-- Removes the first element from the list which is equal to the other argument
delete1 :: Eq a => a -> [a] -> [a]
delete1 x xs = cata (const []) (\el k found -> if not found && el == x then k True else el : k found) xs False

-- Removes the first element from the list which is equal to the other argument
delete2 :: Eq a => a -> [a] -> [a]
delete2 x xs = para [] (\el raw processed -> if el == x then raw else el : processed) xs
看看
delete1
delete2
相比有多尴尬。你不仅需要通过将
cata
的结果变成一个函数来扭曲你的逻辑,而且还需要非常实际的操作成本。你必须在找到匹配的元素后遍历列表中的所有内容,然后重新创建所有
(:)
构造函数。这在效率上会有显著的成本。相比之下,
delete2
,当它找到目标元素时,可以只使用列表的现有尾部,而不用查看它。当然,
foldr
的大多数用法(现实世界,不是这个示例)不生成函数,也不希望访问列表中未处理的尾部。对于他们来说,由于传递的数据较少,所以类同构将稍微更有效

所以在理论上,它们是等价的。在操作上,每一种都有其用途,尽管反射更为常见


对于更一般的概念的一些扩展,请参见库。它使用了一种外观完全不同的概念表述,这样它就可以抽象出具有不同形状的数据类型,而不需要对每个可以应用的数据类型使用不同的
cata
/
para
。但它实际上只是一种替代方法将相同的思想打包的方法,以及其他类型的态射也包括在内,包括许多(甚至)态射。

将准态射(本身)描述为“用原始递归撕裂结构”的东西.一个缺点:许多实际使用的
foldr
都会产生一个函数!这在您希望通过列表计算从左到右传递某些“状态”时非常有用。