2

假设我想在 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’
4

2 回答 2

11

这不是你应该在 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或多个函数方程)会更清楚。

于 2018-09-25T23:36:50.737 回答
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

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

于 2018-09-25T23:34:34.787 回答