【问题标题】:Beginning Haskell - getting "not in scope: data constructor" error开始 Haskell - 出现“不在范围内:数据构造函数”错误
【发布时间】:2011-04-05 06:24:49
【问题描述】:

我正在研究 Haskell O'Reilly 书中的问题。我正在处理的问题是

Using the binary tree type that we defined earlier in this chapter, 
write a function that will determine the height of the tree. The height 
is the largest number of hops from the root to an Empty. For example, the 
tree Empty has height zero; Node "x" Empty Empty has height one; 
Node "x" Empty (Node "y" Empty Empty) has height two; and so on.

我在一个名为 ch3.hs 的文件中编写我的代码。这是我的代码:

36 data Tree a = Node a (Tree a) (Tree a)
37             | Empty
38               deriving (Show)
39
40 --problem 9:Determine the height of a tree
41 height :: Tree -> Int
42 height (Tree node left right) = if (left == Empty && right == Empty) then 0 else max (height left) (height right) 

在终端中打开 ghci 并输入 :load ch3.hs。当我这样做时,我收到以下错误:

Prelude> :load ch3.hs
[1 of 1] Compiling Main             ( ch3.hs, interpreted )

ch3.hs:42:7: Not in scope: data constructor `Tree'
Failed, modules loaded: none.

我希望 Tree 数据构造函数应该在那里,因为我在 height 方法上方的行中定义了它。但是当我尝试加载文件时,我被告知数据构造函数不在范围内。感谢您对为什么会发生此错误的帮助和解释。谢谢, 凯文

【问题讨论】:

    标签: haskell scope


    【解决方案1】:

    改变

    height (Tree node left right) 
    

    height (Node node left right)
    

    这意味着模式匹配适用于algebraic data type (ADT) 的构造函数。 Tree 不是构造函数,它是 ADT 的名称。

    顺便说一句,你必须注释掉你的函数签名声明来编译代码,因为它包含一个错误。

    然后您可以通过

    检查推断的类型 :t 高度

    ghcihugs

    【讨论】:

    • 谢谢,成功了。我仍然不完全了解发生了什么,现在在运行时出错,但会继续盯着、思考和调试。
    • 另一个例子可能更容易理解。让我们假设我们正在处理整数,而不是树。 Int 是整数类型的名称。您不能添加“Int + Int”,因为 Int 是类型的名称,而不是返回该类型值的构造函数。像 0, 1, 2, ... 之类的东西是构造函数,如果您想使用整数,这就是您将它们放入程序的方式。将此应用于您的案例,Tree 是该类型的名称,Node(或 Empty)是您获取该类型 of 值的方式。
    • HaskellWiki 也有一个很有帮助的部分,它甚至以 Tree 为例:haskell.org/haskellwiki/Constructor
    • @KevinBurke 另一种思考方式是'data Bool = True |错误的'。只导入 True 或 False 是没有意义的。需要导入 Bool 本身以允许访问 True 和 False。
    【解决方案2】:

    您与Tree ADT 的 构造函数(即 case)进行模式匹配。 Tree 就是它们的总和。

    这样更直接,,最重要的是,正确:

    height Empty = 0
    height (Node _ l r) = 1 + max (height l) (height r)
    

    【讨论】:

    • -1 这是错误的。使用height (Node 1 (Node 2 Empty Empty) (Node 3 Empty Empty)) 进行测试。应该是 2,是 0 - 任何输入都是 0,因为 OP 有同样的错误。
    • 谢谢。我仍在尝试习惯模式匹配。我将另一个答案标记为正确,因为问题是关于数据构造函数的,但这也很有帮助。
    • 已修复 - 需要在 max (height left) (height right) 的值上加 1,这样它就不会继续返回 0。
    【解决方案3】:

    您的代码在多个级别上都存在错误。您似乎误解了代数数据类型。

    • 类型签名错误,Tree 始终是特定类型的Tree - 您在其声明中称为a,并且可以是任何类型(因为您没有对其进行约束)。所以heigth 必须采用某种类型的Tree - 也是Tree SomeType。您可以并且应该为SomeType 使用最通用的类​​型,即像a 这样的类型变量。
    • 当模式匹配时,您指定一个特定的构造函数 - Node a (Tree a) (Tree a)Empty - 来匹配,而不是整个类型。所以height (Node ...) 会匹配Nodeheight (Empty) 会匹配Emptyheight (Tree ...) 会尝试匹配名为Tree 的构造函数,但没有。这就是您收到的错误消息。
    • 您永远比较(通过==)与构造函数。如果您写deriving (Show, Eq),它实际上会起作用。但是您应该使用模式匹配来确定您是否达到了Empty
    • 这导致:您只匹配 Node,而不是 Empty - 您应该为 Empty 添加一个子句。
    • 此外,如果您解决了上述所有问题,您的函数仍会为所有输入返回 0。除了 0 或孩子们的height 的最大值之外,你永远不会返回任何东西——反过来,它只能返回 0 或孩子们的 height 的最大值,等等。您必须在每个级别增加结果;)

    【讨论】:

    • 感谢您的帮助。我刚开始不久,还在适应新语言。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多