【问题标题】:How to write a function of type a-> b -> b -> b for folding a tree如何编写 a-> b -> b -> b 类型的函数来折叠树
【发布时间】:2016-10-10 22:14:04
【问题描述】:

一些背景知识:我在 Haskell 中有以下类型的 foldT 函数(类似于 foldr,但用于树)。

foldT :: (a -> b -> b -> b) -> b -> Tree a -> b 

这个 foldT 只接受 type (a -> b -> b -> b) 作为输入函数。

我正在尝试找到一种方法将我的树转换为列表,但无法找到使我的附加函数采用 (a -> b -> b -> b) 形式的方法。

以下是无效的,因为它不是正确的类型:

append x y z = append x:y:z 

任何帮助将不胜感激。

谢谢!

【问题讨论】:

  • 虽然foldT 的类型可以做出很好的猜测,但您应该添加树数据类型的定义。
  • 您可能想要toList = foldT (\c l r -> l ++ [c] ++ r) [] 之类的内容,尽管您没有告诉我们您希望按顺序、预购还是后购的转化列表。
  • 第一个参数 做什么 与它的参数?似乎它几乎可以肯定地复制了foldT 本身已经做的一些事情:递归地对子树做它对根所做的事情,并将三者结合起来。

标签: haskell tree append fold


【解决方案1】:

由于你还没有发布它,我假设你的树是......

data Tree a = Leaf | Node a (Tree a) (Tree a)

... 并且 foldTa -> b -> b -> b 参数采用 Node 构造函数的字段,其顺序与声明它们的顺序相同。

我正在尝试找到一种将我的树转换为列表的方法

让我们通过以下类型开始解决这个问题:

foldT :: (a -> b -> b -> b) -> b -> Tree a -> b

你想把它展平成一个列表,所以你的函数的结果类型必须是[a]

treeToList :: Tree a -> [a]

这给了我们如何继续的好主意:

treeToList t = foldT f z t

与:

f :: a -> [a] -> [a] -> [a]
z :: [a]
t :: Tree a

现在,继续讨论。 z 将被插入以代替无价值的Leafs,因此它必须是[]。至于f,它必须将左右分支创建的子列表与Node中的值直接结合起来。假设按顺序遍历,我们有:

 treeToList t = foldT (\x l r -> l ++ x : r) [] t

或者,不提t

 treeToList = foldT (\x l r -> l ++ x : r) []

就是这样。一个警告是重复使用左嵌套的(++)(在这种情况下会发生,因为foldT 递归地沿着分支走)可能会变得非常低效。在您关心性能的情况下,值得考虑实现连接函数的替代方法,例如difference lists

P.S.:关于术语的说明。说一个函数“像 foldr 但用于树”是模棱两可的,因为有两种众所周知的函数类似于foldr。首先,您拥有Foldable 类的方法(参见Benjamin Hodgson's answer),无论您做什么,它都会在折叠树时将其展平为一个列表。然后是更强大的catamorphisms,比如你正在使用的foldT,它们能够利用树形结构。

【讨论】:

    【解决方案2】:

    糟糕,你为什么要写代码? GHC 可以自动填写the Foldable class 的实例,其中包含您要查找的toList

    {-# LANGUAGE DeriveFoldable #-}
    import Data.Foldable
    
    data Tree a = Leaf | Node a (Tree a) (Tree a) deriving Foldable
    
    treeToList :: Tree a -> [a]
    treeToList = toList
    

    由于Node 构造函数的字段顺序,treeToList 的此定义将执行pre-order traversal

    【讨论】:

    • 谢谢,但我的任务要求我为树编写自己的文件夹。
    • 我收到以下代码错误:error: Variable not in scope: toList :: Tree a -> [a]。我正在使用 GCH 8.4.4。
    • @user2023370 谢谢,修复了代码。我忘了导入模块
    【解决方案3】:

    如果要将树转换为列表,则该功能相对简单, 所以基本上如果你有树结构,例如:

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

    然后你必须从树中提取值并将第一个值添加到一个空列表中,然后在列表 (++) 运算符的帮助下递归地将相同的方法应用于树的其他分支将所有结果附加到一个列表中,即:

    toList :: Tree a -> [a]
    toList Leaf                    =    []
    toList (Node left value right) =    [value] ++ toList left ++ toList right
    

    然后折叠它,首先:

    foldT :: (a -> b -> b -> b) -> b -> Tree a -> b
    

    函数签名在这里缺少一个参数让我们看一下签名:a(第一个参数)-> b(第二个)-> b(第三个)-> b(返回类型)函数接受 3 个参数/parameters 但您提供的签名 只有 1 b 类型(我猜这是您的累加器),所以基本上这是您正在寻找的函数签名:

    foldT :: (a -> b -> b) -> b -> Tree a -> b
    

    现在我们可以使用这个签名,然后让我们进入函数:

    foldT :: (a -> b -> b) -> b -> Tree a -> b
    foldT f acc Leaf                    =   acc
    foldT f acc (Node left value right) =   foldT f (foldT f (f value acc) left) right
    

    虽然我不认为我应该给你答案,你应该多练习一下递归数据结构,这样你就可以更好地理解如何遍历它们。

    PS:如果你要对我投反对票,那么至少解释一下原因!

    【讨论】:

    • 我没有,但我猜你会因为提供错误答案而被否决。或者你“认为我不应该给你答案”,因为这是一个问答网站,所以如果有重点的话,请提供答案......
    • @Jack 我知道这是旧的并且已经有一段时间了,但答案是正确的,我确实提供了答案。我只是被一个可能不喜欢我写“我不认为我应该给你答案”的有趣的家伙投票给了我,但我有理由这么说。
    【解决方案4】:

    您每次开始的第一件事就是开始匹配模式 :) 那时,它几乎是机械的!

    假设你有:

    data Tree a = Leaf | Node (Tree a) a (Tree a)
    

    让我们开始匹配模式吧! :)

    foldT :: (a -> b -> b -> b) -> b -> Tree a -> b
    foldT f z ...
    

    第一个Tree 构造函数是什么?我是Leaf

    foldT :: (a -> b -> b -> b) -> b -> Tree a -> b
    foldT f z Leaf = ...
    

    我们可以放什么?我们需要b...类型的东西,而我们只有一种方法可以得到它。通过使用z :)

    foldT :: (a -> b -> b -> b) -> b -> Tree a -> b
    foldT f z Leaf = z
    

    因此,机械地,我们可以继续下一个可能的模式:

    foldT :: (a -> b -> b -> b) -> b -> Tree a -> b
    foldT f z Leaf           = z
    foldT f z (Node t1 x t2) =
    

    好吧,我们可以让它z,但这有点无聊。我们可能想要使用t1xt2。我们可以使用f,它需要a 类型的东西......我们有x :: a :)

    foldT :: (a -> b -> b -> b) -> b -> Tree a -> b
    foldT f z Leaf           = z
    foldT f z (Node t1 x t2) = f x ??? ???
    

    f 还有两个b 类型的参数,那么你认为我们可以放什么?我们可以输入两次z,但这有点无聊。我们如何从t1t2 获得b

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-25
      • 2020-03-03
      • 2017-04-19
      • 2012-03-18
      • 2012-04-07
      • 2013-05-26
      • 1970-01-01
      相关资源
      最近更新 更多