Haskell模式与守卫匹配

时间:2018-09-25 23:14:36

标签: haskell pattern-matching guard-clause

假设我想用

在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’

2 个答案:

答案 0 :(得分:7)

  

这不是您应该在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语言扩展名)。这也许最接近您的原始尝试。

也就是说,可以通过使用<-将图案嵌入防护中。这就是所谓的“图案守卫”:

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

但是,此语法在这里并不能给您带来多少好处。您仍然必须给自变量一个名称(在这种情况下为x),并且必须在任何地方明确说出<- x。直接使用模式匹配(使用case或多个函数方程式)会更清楚。

答案 1 :(得分:2)

如注释中所示,这是不正确的模式匹配。这是一种实现您想要的目标的方法:

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

这表明Guard语句中的表达式必须为Bool类型,但是您要提供TreeNullNode)。