【问题标题】:Summing an Integer Tree (Haskell)对整数树求和(Haskell)
【发布时间】:2015-12-20 05:17:23
【问题描述】:

我正在尝试创建一个对非二进制整数树的值求和的函数。

-- datastructures.hs    
data Tree a = Empty | Node a [Tree a] deriving (Eq, Show)

myNums :: (Num a) => Tree a
myNums = Node 1 [ 
           Node 2 [ 
             Node 4 [Empty], Node 5 [Empty]
           ], 
           Node 3 [
             Node 6 [Empty], Node 7 [Empty], Node 8 [Empty] 
           ]
        ]

addNums :: (Num a) => Tree a -> a
addNums Empty = 0
addNums (Node n [Empty]) = n
addNums (Node n (x:xs)) = n + (addNums x) + (addNums xs)

理想情况下,我希望 addNums myNums 成为 36,但这会产生错误:

datastructures.hs:20:54:
    Couldn't match expected type ‘Tree a’ with actual type ‘[Tree a]’
    Relevant bindings include
      xs :: [Tree a] (bound at datastructures.hs:20:20)
      x :: Tree a (bound at datastructures.hs:20:18)
      n :: a (bound at datastructures.hs:20:15)
      addNums :: Tree a -> a (bound at datastructures.hs:18:1)
    In the first argument of ‘addNums’, namely ‘xs’
    In the second argument of ‘(+)’, namely ‘(addNums xs)’

我该如何应对,最佳做法是什么?

编辑:最佳实践似乎完全省略了Empty!我忘了[][Tree a] 类型的有效实例。所以最好的实现方式是:

data Tree a = Node a [Tree a] deriving (Eq, Show)

addNums :: (Num a) => Tree a -> a
addNums (Node n []) = n
addNums (Node n (x:xs)) = n + (addNums x) + addNums (Node 0 xs)

【问题讨论】:

  • (addNum x) + (addNum xs)。不能工作。 xxs 在这里是不同的类型。
  • 这也不起作用:addNums (Node n (x:xs)) = n + (addNums x) + foldl1 (\ acc t -> acc + addNums t) xs
  • addNums (Node n xs) = foldl (\a -> (+) a . addNums) n xs
  • 另请注意,您的树具有冗余表示。 Node 1 []Node 1 [Empty]Node 1 [Empty,Empty,Empty] 都代表同一棵树。也许你想改变它,或者至少处理[] 的情况。
  • @MarkKaravan 请注意,如果您删除 Empty,每棵树都必须包含至少一个元素 n

标签: haskell data-structures tree


【解决方案1】:

只需派生Foldable 并使用现有的sum

{-# LANGUAGE DeriveFoldable #-}

data Tree a = Empty | Node a [Tree a] deriving (Eq, Show, Foldable)

myNums :: (Num a) => Tree a
myNums = ...

main = print $ sum myNums

【讨论】:

  • @Mark Karavan,yes,以及其他答案,它泄漏了。您可以使用fasterSum = foldl' (+) 0foldl' 也附带Foldable),但如果它也泄漏,我不会感到惊讶。您可以打开另一个关于树中数字的有效求和的问题。
【解决方案2】:

一个可能的解决方案:

addNums :: (Num a) => Tree a -> a
addNums Empty = 0
addNums (Node n xs) = n + sum (map addNums xs)

在递归的情况下,我们有一个树列表xs。我们可以在每棵树上使用addNums,获得一个数字列表。然后,我们简单地把它们加起来,加上根n

【讨论】:

    【解决方案3】:

    问题出在addNums 定义的最后两行。您必须检查空的基本情况,而不是当列表包含一个带有 Empty 的元素时。像这样的东西应该可以工作:

    addNums :: (Num a) => Tree a -> a
    addNums Empty = 0
    addNums (Node n []) = n
    addNums (Node n (x:xs)) = n + (addNums x) + addNums (Node 0 xs)
    

    请注意,对于一个空列表,您只是返回 n。当列表包含多个元素时,您递归地对其求和,直到它达到 bae 案例(即列表变为空)。

    ghci中的演示:

    λ> addNums myNums
    36
    

    【讨论】:

    • 我花了一分钟才明白为什么你需要[] 模式(因为任何[Tree a] 必须至少包含一个Empty,但现在我看到你正在根据你自己的评估它Node 0。这看起来很尴尬;这种树有最佳实践吗?
    • @MarkKaravan 即使这样你也必须检查[] 的大小写,否则你的模式匹配将不是详尽的。正如 user2407038 所展示的那样,您可以使用 foldl 抽象整个事物。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-29
    • 1970-01-01
    • 1970-01-01
    • 2011-06-01
    • 2013-05-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多