原语递归直接对应于一个paramorphism。
您是正确的,变质具有与异质性等效的理论能力,但是在操作方面它们可能在重要方面有所不同。例如,让我们使用列表而不是 Nats。
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
每个可以应用的数据类型使用不同的类型。但这实际上只是打包相同想法的另一种方式,并且还涵盖了其他类型的态射,包括更 多利基(甚至可能无用)的态射。