禁止代码示例(我希望能够编写):
isWaiting :: Eq a => a -> PriorityQueue a -> Bool
isWaiting x EmptyQueue = False
isWaiting x (Push x y p) = True
isWaiting x (Push z y p) = isWaiting x p
相同的逻辑,但有效的变体:
isWaiting :: Eq a => a -> PriorityQueue a -> Bool
isWaiting x EmptyQueue = False
isWaiting x (Push z y p) = if x == z then True else isWaiting x p
答案 0 :(得分:14)
处理非线性模式将需要确定两个要匹配的项是否相等。通常,我们不能这样做:
areFunctionsEqual :: (Integer->Integer) -> (Integer->Integer) -> Bool
areFunctionsEqual f f = True
areFunctionsEqual _ _ = False
由于我们无法比较函数,因此上述内容实际上是不允许的。
然而,人们可能会奇怪为什么Eq
类中的类型不允许这样做,而可判定性不是问题。那将允许一个人写
foo x y x = ...
代替
foo x y z | z==x = ...
这很难证明。有人可能会辩称,第一个非线性模式可能是偶然编写的,并引入了细微的错误。第二个不再那么长,并且可以更好地记录意图。
我认为这是否是一个很好的论点是个人观点。
另一个微妙的论点:
foo x y z | z==x = bar x
在符号上等同于
foo x y z | z==x = bar z
,但是这两个变体仍可能导致不同的内存占用,因为在较大的程序中,第一个可能允许z
被垃圾收集,而第二个可能允许x
被垃圾收集。如果说z
已经在程序中的其他地方被引用,我们想使用第二种形式,这样x
就被垃圾回收了。第一种形式将导致x
和z
都保留在内存中。
如果我们可以写foo x y x = bar x
,那将被垃圾回收吗?
不太清楚。
可以说,这是一个很小的要点,因为如果控制垃圾收集如此重要,则仍然可以使用显式变体。
答案 1 :(得分:7)
某些具有模式匹配的语言(例如Prolog,Erlang)允许
isWaiting x (Push x y p) = True
表示仅在两个模式变量x
相等时模式才匹配。
哈斯克尔没有。如果愿意,您可以阅读Pattern Matching - Prolog vs. Haskell。
使用警卫的工作变体的替代方案如下:
isWaiting :: Eq a => a -> PriorityQueue a -> Bool
isWaiting x EmptyQueue = False
isWaiting x (Push z y p)
| x == z = True
| otherwise = isWaiting x p
使用(||)
运算符而不是 if-then-else 的操作符看起来像:
isWaiting :: Eq a => a -> PriorityQueue a -> Bool
isWaiting x EmptyQueue = False
isWaiting x (Push z y p) = x == z || isWaiting x p
编辑:和使用丹尼尔·瓦格纳(Daniel Wagner)推导Foldable
的提议的人:
{-# LANGUAGE DeriveFoldable #-}
type Priority = ...
data PriorityQueue a
= EmptyQueue
| Push a Priority (PriorityQueue a)
deriving (Foldable)
isWaiting :: Eq a => a -> PriorityQueue a -> Bool
isWaiting = elem