【问题标题】:Sum of tree in haskell [duplicate]Haskell中树的总和[重复]
【发布时间】:2021-10-02 19:38:26
【问题描述】:

我尝试了以下代码,但我得到一个错误 a 与预期的类型“Integer”不匹配。

data Tree a = Tip | Bin (Tree a) a (Tree a)

sumTree :: Num a => Tree a -> a

sumTotal = 0
sumTree Tip = 0
sumTree (Bin l a r) = (sumTotal+ a)+ sumTree l + sumTree 

【问题讨论】:

    标签: haskell tree sum


    【解决方案1】:

    在 Haskell 中没有可变变量,所以 sumTotalsumTotal + 没有意义。通常在 Haskell 中,使用递归作为访问树中项目的机制。因此,您可以将sumTree 实现为:

    sumTree :: Num a => Tree a -> a
    sumTree Tip = 0
    sumTree (Bin l a r) = a + sumTree l + sumTree r

    对于具有两层的树,这将因此在左右子树上执行递归。对于像Bin (Bin Tip 1 (Bin Tip 4 Tip)) 2 (Bin Tip 5 Tip) 这样的树,这将评估为:

       sumTree Bin (Bin Tip 1 (Bin Tip 4 Tip)) 2 (Bin Tip 5 Tip)
     → 2 + sumTree (Bin Tip 1 (Bin Tip 4 Tip)) + sumTree (Bin Tip 5 Tip)
     → 2 + (1 + sumTree Tip + sumTree (Bin Tip 4 Tip)) + sumTree (Bin Tip 5 Tip)
     → 2 + (1 + 0 + (4 + sumTree Tip + sumTree Tip)) + sumTree (Bin Tip 5 Tip)
     → 2 + (1 + 0 + (4 + 0 + sumTree Tip)) + sumTree (Bin Tip 5 Tip)
     → 2 + (1 + 0 + (4 + 0 + 0)) + sumTree (Bin Tip 5 Tip)
     → 2 + (1 + 0 + 4) + sumTree (Bin Tip 5 Tip)
     → 2 + 5 + sumTree (Bin Tip 5 Tip)
     → 2 + 5 + (5 + sumTree Tip + sumTree Tip)
     → 2 + 5 + (5 + 0 + sumTree Tip)
     → 2 + 5 + (5 + 0 + 0)
     → 2 + 5 + 5
     → 7 + 5
     → 12

    您还可以使用DeriveFoldable extension [ghc-doc]Tree 设为Foldable 的实例(或自己实现Foldable 实例)。在那种情况下,sumTree 只是sum :: (Foldable f, Num a) => f a -> a 的一个特例:

    {-# LANGUAGE DeriveFoldable #-}
    
    data Tree a = Tip | Bin (Tree a) a (Tree a) deriving Foldable
    
    sumTree :: Num a => Tree a -> a
    sumTree = sum

    【讨论】:

    • 非常感谢!这是一个愚蠢的错误。谢谢你解释得这么清楚
    【解决方案2】:

    该错误是由对sumTotal 的引用引起的,该引用在多态函数sumTree 中使用时获得了单态类型。

    您的帖子中还有一个复制粘贴错字,在

    sumTree (Bin l a r) = (sumTotal+ a)+ sumTree l + sumTree
    

    但你实际上必须有

    sumTree (Bin l a r) = (sumTotal+ a)+ sumTree l + sumTree r
    

    在你的代码中,否则你会得到一个不同的错误。


    sumTotal 实际上根本不需要,因为它始终是0,所以它没有任何改变。你可以从任何地方完全删除它,当你这样做时,错误就会消失,函数就会正常工作。

    但是添加0 应该不会有什么坏处,你问?是的,但是有限制,变量sumTotal 得到一个单态,即特定类型,如Integer。而你的函数sumTree 被声明为多态的,所以保持这种状态。将固定类型值添加到灵活类型值是没有意义的。

    在 Haskell 中,没有在运行时改变值的类型转换。所有类型都是预先知道的。当我们将两个“灵活”的多态类型值相加时,结果是相同的类型,因此当实际确定该类型具体是什么时,它将被一致地分配给所有三个匹配项。但是,当您从一开始就在其中一个中使用特定类型时,您会阻止这种同步性。

    但是,你说,添加0 不应该破坏事情。在不更改代码的情况下如何避免错误?

    为此,您需要禁用单态限制。

    在 GHCi 中,使用

    > :set -XNoMonomorphismRestriction
    

    然后使用:{:} 命令以多行输入模式重新输入您的定义。

    或者在你的源代码文件中添加

    {-# LANGUAGE NoMonomorphismRestriction #-}
    

    在最顶端。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-24
      • 2013-07-04
      • 2018-07-02
      相关资源
      最近更新 更多