【问题标题】:Haskell pattern matching with guardsHaskell 模式匹配守卫
【发布时间】:2019-03-01 15:29:22
【问题描述】:

假设我想用

在 Haskell 中建模一个树结构
data Tree = Null | Node Tree Integer Tree deriving Show

我想测试每个条目是否小于 10。我想我会使用模式匹配并编写

isSmall :: Tree -> Bool
isSmall _ 
  | Null = True
  | (Node a b c) = if b >= 10
                   then False
                   else isSmall a && isSmall c

但是它给出了关于abc 超出范围的错误。我原以为将它们放在警卫中基本上会将它们放在范围内。这不是你应该在 Haskell 中进行模式匹配的方式吗?我环顾四周寻找可以指导我的示例,但我没有在使用由其他几种数据结构组成的数据结构的守卫中找到任何模式匹配示例。

错误:

test.hs:24:6: Not in scope: data constructor ‘Node’

test.hs:24:11: Not in scope: ‘a’

test.hs:24:13: Not in scope: ‘b’

test.hs:24:15: Not in scope: ‘c’

test.hs:24:27: Not in scope: ‘b’

test.hs:26:38: Not in scope: ‘a’

test.hs:26:57: Not in scope: ‘c’

【问题讨论】:

  • 你能发布确切的错误吗?
  • @DavOS 编辑了错误。
  • 你为什么要把图案放在守卫里?
  • "这不是你应该在 Haskell 中进行模式匹配的方式吗?" 不。守卫是布尔表达式,而不是模式。
  • if A then False else B 最好写成not A && B

标签: haskell pattern-matching guard-clause


【解决方案1】:

如 cmets 所示,这是不正确的模式匹配。这是实现您似乎正在寻找的一种方法:

isSmall :: Tree -> Bool
isSmall Null         = True
isSmall (Node a b c) = if b >= 10
                       then False
                       else isSmall a && isSmall c

按照您在问题中发布的方式进行操作,您还会遇到另一个错误:

* Couldn't match expected type `Bool' with actual type `Tree'
* In the expression: (Node a b c)
  In a stmt of a pattern guard for
                 an equation for `isSmall':
    (Node a b c)
  In an equation for `isSmall':
      isSmall _
        | Null = True
        | (Node a b c) = if b >= 10 then False else isSmall a && isSmall c

这表示保护语句中的表达式必须是 Bool 类型,但您提供的是 TreeNullNode)。

【讨论】:

  • 所以这就是我把它变成的,但现在它仍然给了我错误Not in scope: data constructor ‘Node’ 的一部分。但是,当我删除 isSmall 函数但保留 Tree(包含 Node)的定义时,它编译得很好。 Tree 的定义实际上是在导入到我的test 文件中的一个文件中——这会导致问题吗?
  • @Addem 在定义Tree 的文件中是否有module 声明?如果有,它是什么样子的?
  • module BinarySearchTrees( Tree(Null) , size, member, insert, toList, eq, treeMin, delete) where
  • 我开始认为我误解了Node 的工作原理。我认为这是一个原始的 Haskell 类型,但现在我认为它是在 Tree 的定义中组成的,因此当我在不导入 Node 的情况下导入 Tree 时,我无法访问 Node。这似乎很奇怪,因为 Node 是 Tree 定义的一部分……但我想它就是这样。
  • @Addem 是的,这表示您要导出Tree 类型及其Null 数据构造函数,而不是Node。你想要Tree(Null, Node)Tree(..)
【解决方案2】:

这不是你应该在 Haskell 中进行模式匹配的方式吗?

没有。守卫是布尔表达式,而不是模式。

你可以像这样进行模式匹配:

isSmall :: Tree -> Bool
isSmall Null = True
isSmall (Node a b c) = b < 10 && isSmall a && isSmall c

...或者像这样:

isSmall :: Tree -> Bool
isSmall x = case x of
  Null -> True
  Node a b c -> b < 10 && isSmall a && isSmall c

...甚至像这样:

{-# LANGUAGE LambdaCase #-}

isSmall :: Tree -> Bool
isSmall = \case
  Null -> True
  Node a b c -> b < 10 && isSmall a && isSmall c

(使用LambdaCase 语言扩展名)。这可能最接近您最初的尝试。

也就是说,可以使用&lt;- 在守卫中嵌入模式。这被称为“模式守卫”:

isSmall :: Tree -> Bool
isSmall x 
  | Null <- x = True
  | Node a b c <- x = b < 10 && isSmall a && isSmall c

但是,这种语法在这里并没有给你带来太多好处。您仍然必须为参数命名(在这种情况下为x),并且您必须在任何地方明确说出&lt;- x。直接使用模式匹配会更清晰(使用case 或多个函数方程)。

【讨论】:

  • 我有一个案例,我想隐式捕获所有内容,但仍然检查匹配的 ADT 构造函数,例如toThing thing | Thing{} &lt;- thing = thing。还有其他方法可以在不明确的情况下捕获全部或部分内容吗?就我而言,这有点像otherwise 条件,但我还是更愿意明确说明情况。
猜你喜欢
  • 2015-08-15
  • 1970-01-01
  • 2011-09-28
  • 2011-04-17
  • 1970-01-01
  • 2014-09-19
  • 2017-06-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多