简体   繁体   English

Haskell模式与守卫匹配

[英]Haskell pattern matching with guards

Suppose I want to model a tree structure in Haskell with 假设我想在Haskell中用

data Tree = Null | Node Tree Integer Tree deriving Show

and I'd like to test if every entry is, say, less than 10. I thought I would use pattern matching and write 我想测试每个条目是否少于10个。我想我会使用模式匹配并编写

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

However it gives errors about a , b , and c being out of scope. 但是,它给出关于abc超出范围的错误。 I would have thought putting them in the guards would basically put them in the scope. 我本以为将它们放在守卫中基本上可以将它们放在范围内。 Is this not how you're supposed to do pattern matching in Haskell? 这不是您应该在Haskell中进行模式匹配的方式吗? I've looked around for examples that would guide me but I haven't found any examples of pattern matching in guards that uses a data structure composed of several other data structures. 我四处寻找可以指导我的示例,但我没有在守卫中使用任何由其他几种数据结构组成的数据结构的模式匹配示例。

The error: 错误:

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’

Is this not how you're supposed to do pattern matching in Haskell? 这不是您应该在Haskell中进行模式匹配的方式吗?

No. Guards are boolean expressions, not patterns. 不。警卫是布尔表达式,而不是模式。

You can do pattern matching like this: 您可以像这样进行模式匹配:

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

... or like this: ...或者像这样:

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

... or even like this: ...甚至是这样的:

{-# LANGUAGE LambdaCase #-}

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

(using the LambdaCase language extension). (使用LambdaCase语言扩展名)。 This is perhaps closest to your original attempt. 这也许最接近您的原始尝试。

That said, it is possible to embed patterns in guards by using <- . 也就是说,可以通过使用<-将图案嵌入防护中。 This is known as "pattern guards": 这就是所谓的“模式卫士”:

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

However, this syntax doesn't buy you much here. 但是,这种语法在这里不会给您带来多少好处。 You still have to give the argument a name ( x in this case) and you have to explicitly say <- x everywhere. 您仍然必须给自变量一个名称(在本例中为x ),并且必须在所有位置明确说出<- x It would be clearer to use pattern matching directly (using case or multiple function equations). 直接使用模式匹配(使用case或多个函数方程式)会更清楚。

As indicated in the comments, this is incorrect pattern matching. 如注释中所示,这是不正确的模式匹配。 Here is one way to achieve what you seem to be looking for: 这是一种实现您似乎正在寻找的方法:

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

You also get another error by doing it the way you posted in the question: 通过按照您在问题中发布的方式执行操作,您还会遇到另一个错误:

* 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

This indicates that the expression inside the guard statements must be of type Bool but you are providing a Tree (either Null or Node ). 这表明guard语句中的表达式必须为Bool类型,但是您正在提供TreeNullNode )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM