【发布时间】:2011-01-17 21:26:49
【问题描述】:
我已经定义了一棵二叉树:
data Tree = Null | Node Tree Int Tree
并实现了一个函数,该函数将产生其所有节点的值的总和:
sumOfValues :: Tree -> Int
sumOfValues Null = 0
sumOfValues (Node Null v Null) = v
sumOfValues (Node Null v t2) = v + (sumOfValues t2)
sumOfValues (Node t1 v Null) = v + (sumOfValues t1)
sumOfValues (Node t1 v t2) = v + (sumOfValues t1) + (sumOfValues t2)
它按预期工作。我也想尝试使用守卫来实现它:
sumOfValues2 :: Tree -> Int
sumOfValues2 Null = 0
sumOfValues2 (Node t1 v t2)
| t1 == Null && t2 == Null = v
| t1 == Null = v + (sumOfValues2 t2)
| t2 == Null = v + (sumOfValues2 t1)
| otherwise = v + (sumOfValues2 t1) + (sumOfValues2 t2)
但是这个不起作用,因为我没有实现Eq,我相信:
No instance for (Eq Tree) arising from a use of `==' at zzz3.hs:13:3-12 Possible fix: add an instance declaration for (Eq Tree) In the first argument of `(&&)', namely `t1 == Null' In the expression: t1 == Null && t2 == Null In a stmt of a pattern guard for the definition of `sumOfValues2': t1 == Null && t2 == Null
那么,必须提出的问题是,Haskell 如何在不知道传递的参数何时匹配的情况下进行模式匹配,而不求助于Eq?
编辑
您的论点似乎围绕着这样一个事实,即 Haskell 并没有真正比较函数的参数,而是在“形式”和签名类型上知道要匹配哪个子函数。但是这个怎么样?
f :: Int -> Int -> Int
f 1 _ = 666
f 2 _ = 777
f _ 1 = 888
f _ _ = 999
在运行f 2 9时,是不是一定要用Eq才能知道哪个子函数是正确的?它们都是相等的(与我最初的 Tree 示例相反,当我们有 Tree/Node/Null 时)。或者Int 的实际定义类似于
data Int = -2^32 | -109212 ... | 0 | ... +2^32
?
【问题讨论】:
-
当您对数字进行模式匹配时,您使用的是
Eq类。数字文字不是构造函数。如果是,他们就不能拥有Num a => a类型。请注意,Num需要Eq。如果您使用时髦的Eq实例定义Num实例,则模式匹配将相应地表现(即,如果(fromInteger 42 :: MyInt) == fromInteger 23为真,则模式23也将匹配值42 :: MyInt)。 -
您知道,并非所有 32 位都可用于表示 Int。在我的机器上,
maxBound :: Int返回 2147483647, 2^31 - 1。 -
是的,我知道。但是对于问题的上下文,我只是不在乎。
-
顺便说一句,如果您需要
Eq进行模式匹配,那么首先自己定义Eq实例会相当困难...... ;-) -
@Wei Hu:实际上,他们有。想一想:maxBound = 2147483647 = 2^31 - 1,minBound = -2147483648 = 2^32,而不是加0,所以你得到:2^31 + 2^31-1 +1 = 2^32,你怎么看想要更多?