12

使用以下自然数的变态,我可以实现各种算术算法,而无需处理递归:

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在我看来类似于原始递归。至少它的每个应用程序似乎都可以终止,无论提供zerosucc的哪种组合。在每次迭代中,整个问题都被最小/最简单的问题实例分解。因此,即使它在技术上不是原始递归,它似乎也具有同样的表现力。如果这是真的,则意味着变态不足以表达一般递归。我们可能需要一个hylomorphism。我的推理是否正确,也就是说,是否对任何类型的变质都成立,而不仅仅是自然数?

4

1 回答 1

5

原语递归直接对应于一个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(现实世界,不是这个例子)的大多数用途都不会产生函数,也不想访问列表的未处理尾部。对他们来说,仅仅因为传递更少的数据,变质将稍微更有效率。

所以就理论能力而言,它们是等价的。在操作方面,每个都有一个用途,尽管变质更为常见。

对于更一般的概念的一些扩展,请参阅递归方案库。它使用了一种看起来完全不同的想法,因此它可以抽象出具有不同形状的数据类型,而不是需要catapara每个可以应用的数据类型使用不同的类型。但这实际上只是打包相同想法的另一种方式,并且还涵盖了其他类型的态射,包括 多利基(甚至可能无用)的态射。

于 2020-06-20T20:58:12.340 回答