Haskell-将玫瑰树的深度优先遍历表示为“展开”的实例,并通过代数推导
假设我们定义了一棵玫瑰树,以及相应的数据类型Haskell-将玫瑰树的深度优先遍历表示为“展开”的实例,并通过代数推导,haskell,tree,fold,unfold,anamorphism,Haskell,Tree,Fold,Unfold,Anamorphism,假设我们定义了一棵玫瑰树,以及相应的数据类型 data RTree a = Node a [RTree a] foldRTree :: (a -> [b] -> b) -> RTree a -> b foldRTree f (Node x xs) = f x (map (foldRTree f) xs) 这种结构的深度优先遍历的递归定义为: dft :: RTree a -> [a] dft (Node x xs) = x : concat (map dft x
data RTree a = Node a [RTree a]
foldRTree :: (a -> [b] -> b) -> RTree a -> b
foldRTree f (Node x xs) = f x (map (foldRTree f) xs)
这种结构的深度优先遍历的递归定义为:
dft :: RTree a -> [a]
dft (Node x xs) = x : concat (map dft xs)
我们可以将dft表示为玫瑰树上的折叠,特别是我们可以通过代数推导出这样的折叠
// Suppose dft = foldRTree f
// Then foldRTree f (Node x xs) = f x (map (foldRTree f) xs) (definition of foldRTree)
// But also foldRTree f (Node x xs) = dft (Node x xs) (by assumption)
// = x : concat (map dft xs) (definition of dft)
// So we deduce that f x (map (foldRTree f) xs) = x : concat (map dft xs)
// Hence f x (map dft xs) = x : concat (map dft xs) (by assumption)
// So we now see that f x y = x : concat y
我想我们之所以能够这样做是因为foldRTree捕获了RTrees上的一般递归结构,这就引出了我对unfold的查询
我们定义如下:
unfold :: (a -> Bool) -> (a -> b) -> (a -> a) -> a -> [b]
unfold n h t x | n x = []
| otherwise = h x : unfold n h t (t x)
// Or Equivalently
unfold' n h t = map h . takeWhile (not.n) . iterate t
dft (Node x xs) = x : unfold null h t xs
where h ((Node a xs) : ys) = a
t ((Node a xs) : ys) = xs ++ ys
我们可以将深度优先遍历表示为展开,如下所示:
unfold :: (a -> Bool) -> (a -> b) -> (a -> a) -> a -> [b]
unfold n h t x | n x = []
| otherwise = h x : unfold n h t (t x)
// Or Equivalently
unfold' n h t = map h . takeWhile (not.n) . iterate t
dft (Node x xs) = x : unfold null h t xs
where h ((Node a xs) : ys) = a
t ((Node a xs) : ys) = xs ++ ys
我正在努力寻找一种方法来发展一种代数计算函数nht的方法,就像cons一样。特别是在开发展开时,有一个巧妙的步骤,即认识到展开的最终参数必须是[RTree a]类型,而不仅仅是RTree a。因此,向dft提出的论点没有直接传递给展开,因此我们在对这两个函数进行推理时遇到了障碍
如果有人能提供一种数学方法来对展开进行推理,从而在将递归函数(自然是折叠)表示为展开(可能使用一些将折叠和展开联系起来的定律)时计算出所需的函数nh和t,我将不胜感激。一个自然的问题是,我们必须用什么方法来证明这种关系是正确的 提示:将内部状态类型为
s
且输出列表类型为[a]
的展开类型定义为类型展开sa=(s->Bool,s->a,s->s,s)
。这些很像列表;您的函数基本上具有类型unfold::unfold s a->[a]
。你会写cons::a->Unfold s a->Unfold吗?您选择的某种类型的
?<代码>地图::(a->b)->展开s a->展开?b<代码>混凝土::展开s(展开s'a)->展开?a?如果您有cons
、map
和concat
,您可以使用相同的定义(但不同的类型)直接写下您的dft
。