我们是否可以定义一种递归方案(而不失去其通用性),以 构造自顶向下的值 ,而不是自底向上?
这将非常有帮助,因为我已经看到很多次使用递归方案在内部定义的函数首先将reverse
应用于其输入,从而明确表明需要foldl
-例如“从前到后”执行。
答案 0 :(得分:11)
尽管普遍认为cata
是“自下而上”的,但实际上它可以通过使用参数为函数的载体实例化载体来表示“自上而下”的构造,该函数的参数是要传递的信息“自上而下”下”:
cata :: (F c -> c ) -> Fix F -> c -- general signature
:: (F (i -> d) -> (i -> d)) -> Fix F -> i -> d -- with c = (i -> d)
这就是使用foldl
(列表的reverse
)来实现foldr
或cata
的方式。
-- foldl :: (b -> a -> b) -> b -> [a] -> b
-- using
-- foldr :: (a -> (b -> b) -> (b -> b)) -> (b -> b) -> [a] -> b -> b
foldl f b xs = foldr (\x go z -> go (f z x)) id xs b
这是另一个从根数开始按深度标记树的示例:
data Tree a = Node (Tree a) a (Tree a) | Leaf
makeBaseFunctor ''Tree -- recursion-schemes
byDepth :: Tree a -> Tree Integer
byDepth t = cata byDepthF t 0 where
byDepthF :: TreeF a (Integer -> Tree Integer) -> Integer -> Tree Integer
byDepthF (NodeF u _ v) !d = Node (u (d + 1)) d (v (d + 1))
byDepthF LeafF = Leaf