【问题标题】:Haskell: Folding over treesHaskell:在树上折叠
【发布时间】:2018-04-11 01:36:22
【问题描述】:

我正在网上学习一些旧课程并遇到了这个任务:

data Tree a = Leaf 
            | Branch a (Tree a) (Tree a) 
            deriving (Show, Eq)

fold :: (a -> b -> b -> b) -> b -> Tree a -> b
fold _ acc Leaf           = acc
fold f acc (Branch v l r) = f v (fold f acc l) (fold f acc r)

foldRT :: (a -> b -> b) -> b -> Tree a -> b
foldRT _ acc Leaf = acc
foldRT f acc (Branch v l r) = foldRT f (f v (foldRT f acc r)) l

任务是用fold 重写foldRT。我已经被它困了很久,无法绕开它。

不胜感激。

【问题讨论】:

  • @pdoherty926 我相信没有更多的东西 - 重构的问题陈述可能是“在变质方面实现类似列表/Foldable-like 折叠 (foldRT) /一般折叠 (fold)"。
  • 参见stackoverflow.com/a/27458645/383200,了解一般技术的讨论。该答案适用于列表,但同样的想法也适用。

标签: haskell


【解决方案1】:

正如其名称和类型签名所暗示的那样,foldRT 是您的树的真正正确折叠(您可以通过手动评估它来说服自己,例如Branch 1 (Branch 0 Leaf Leaf) (Branch 2 Leaf Leaf))。这意味着实现Foldable 会给你foldRTfoldRT = foldr。为什么这是相关的?因为,在这种情况下,实现foldMap 比直接弄清楚如何编写foldr 要容易得多:

-- Note that l and r here aren't the subtrees, but the results of folding them.
instance Foldable Tree where
    foldMap f = fold (\v l r -> l <> f v <> r) mempty

如果你想在不依赖Foldable 实例的情况下编写foldRT,你所需要的只是扩展foldr 的基于foldMap 的定义(有关详细信息,请参阅this question 的答案在这里掩饰):

foldRT f z t = appEndo (foldMap (Endo . f) t) z

-- To make things less clumsy, let's use:
foldEndo f = appEndo . foldMap (Endo . f)
-- foldEndo f = flip (foldRT f)

foldEndo f = appEndo . fold (\v l r -> l <> Endo (f v) <> r) mempty

-- As we aren't mentioning foldMap anymore, we can drop the Endo wrappers.
-- mempty @(Endo _) = Endo id
-- Endo g <> Endo f = Endo (g . f)
foldEndo f = fold (\v l r -> l . f v . r) id

-- Bringing it all back home:
foldRT :: (a -> b -> b) -> b -> Tree a -> b
foldRT f z t = fold (\v l r -> l . f v . r) id t z

(请注意,我们最终仅通过间接途径达到了suggested by Carl 之类的解决方案。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-04
    • 1970-01-01
    • 2015-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多