>假设我想在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
但是,它给出了有关a
、b
和c
超出范围的错误。 我本以为把他们放在警卫中基本上会把他们放在瞄准镜里。 这不是你应该在 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’
这不是你应该在 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
或多函数方程(会更清楚。
如注释中所述,这是不正确的模式匹配。这是实现您似乎正在寻找的目标的一种方法:
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
,但您提供的是Tree
(Null
或Node
(。