为什么不能在模式匹配中使用++?

时间:2014-04-21 20:20:15

标签: list haskell pattern-matching

来自LearnYouAHaskell:

  

还有一件事 - 你不能在模式匹配中使用++。如果你试图模式匹配(xs ++ ys),那么第一个和第二个列表中的内容是什么?这没有多大意义。匹配(xs ++ [x,y,z])或只是(xs ++ [x])的东西是有意义的,但由于列表的性质,你不能这样做。

我很难通过列表的性质来解释他的意思,为什么这不可能。

2 个答案:

答案 0 :(得分:8)

您对构造函数进行模式匹配,对于列表,有两个构造函数,空列表[]和' cons' :,其中cons有两个参数,列表的头部和尾部。 ++是附加两个列表的功能,因此您无法与之匹配。

如果您可以匹配,则模式xs中的ysxs ++ ys会有多个匹配项。例如,如果您选择了[1]这样的小列表,那么就有两种可能性

xs == [] and ys == [1]
xs == [1] and ys == []

因此匹配是模棱两可的,这就是引用的内容。

答案 1 :(得分:4)

您只能对数据构造函数进行模式匹配。这令人困惑,因为Haskell中的List类型依赖于某些合成糖。因此,让我们删除它并定义我们自己的List类型,以便更容易看到发生了什么。

data List a = Nil | Cons a (List a)

现在,当您想声明一个使用此List类型的函数时,您可以在构造函数上进行模式匹配。

myHead :: List a -> Maybe a
myHead Nil = Nothing
myHead (Cons a as) = Just a

这是默认情况下唯一可以进行的模式匹配。 Haskell中的列表使用一些糖实现,将Cons重命名为(:),将Nil重命名为[]。并且它允许您以[a, b, c]符号编写列表,但从根本上说,这些事情是相同的。

另一方面,

(++)是正常函数,而不是数据构造函数。

我对您尝试做的事情的猜测是查看列表中的前几个元素,并将它们与列表的其余部分分开。您可以使用常规模式匹配以非常简单的方式执行此操作。

getFirstThree :: [a] -> Maybe (a, a, a)
getFirstThree (a1:a2:a3:as) = Just (a1, a2, a3)
getFirstThree _ = Nothing

如果可以模式匹配正常函数,这与写作相同:

getFirstThree :: [a] -> Maybe (a, a, a)
getFirstThree ([a1, a2, a3] ++ as) = Just (a1, a2, a3)
getFirstThree _ = Nothing

也许第二个定义对你来说更清楚了。我不相信这是列表的情况,但还有其他数据类型可能是这样。对于这类事情,存在ViewPatternsPatternSynonyms扩展,并且可以通过基本告诉编译器 如何执行<{1}}来将(++)定义为可匹配模式模式匹配。但是,正如@Lee所说,这种匹配是不明确的,因为任何给定模式都有多个有效匹配,看起来像(a ++ b)