Haskell 和 Erlang 中的模式匹配

Posted

技术标签:

【中文标题】Haskell 和 Erlang 中的模式匹配【英文标题】:Pattern-matching in Haskell and Erlang 【发布时间】:2017-07-09 15:04:27 【问题描述】:

我有一个小的 Erlang 函数来比较两个列表是否相等:

myEq([], [])         -> true;
myEq([X|Xs], [X|Ys]) -> myEq(Xs, Ys);
myEq(_, _)           -> false.

比较发生在第 2 行,[X|Xs]X 始终绑定到第一个列表的第一个元素,[X|Ys] 仅在两个列表的第一个元素相等时才匹配。

如果我在 Haskell 中尝试此操作,我会收到一条错误消息:“x的定义冲突”。 Haskell 中一个可能的解决方案是:

myEq (x:xs) (y:ys) = if x == y then myEq xs ys else False

但我想知道是否可以在 Haskell 中使用模式匹配来做到这一点?

【问题讨论】:

【参考方案1】:

不,在 Haskell 中,您不能在子句的头部使用相同的变量 x。 Haskell unification平等检查 分别像 PrologErlang做。这在Haskell '98 报告中指定:

每个匹配对应的模式集合必须是线性的---变量在整个集合中不能出现多次

(复制,加粗)

做到这一点的唯一方法是使用守卫(当然也可以使用任何其他类型的检查主体)。但是,您可以将其写得更优雅:

myEq [] [] = True
myEq (x:xs) (y:ys) | x == y = myEq xs ys
--                 | otherwise = False
myEq _ _ = False

otherwise 的大小写可以省略,因为 Haskell 将回退到最后一个子句并因此返回 False

或者更优雅:

myEq [] [] = True
myEq (x:xs) (y:ys) = x == y && myEq xs ys
myEq _ _ = False

我个人认为这更好,因为您在这里明确声明x 等于y,因此不会发生像意外写入相同变量这样的错误。虽然这当然是一个品味问题。

【讨论】:

澄清一下:Erlang 也不做统一。如果一个变量在一个模式中出现多次,Erlang 编译器会简单地为其他出现的变量生成新名称,并插入一个要求它们相等的保护测试,就像您在 Haskell 中手动执行的操作一样。 @RichardC:我重写了统一平等检查的答案。你认为这能更好地解决这个问题吗? 是的,看起来更好。【参考方案2】:

没有。每个变量在模式匹配端最多可以绑定一次。如果您想绑定一个变量两次,则必须进行求值以执行统一。

【讨论】:

以上是关于Haskell 和 Erlang 中的模式匹配的主要内容,如果未能解决你的问题,请参考以下文章

函数返回与函数参数中的 Haskell 模式匹配

Haskell:绑定模式匹配的地方

什么是 Erlang 中的模式匹配

为啥 Erlang 中的模式匹配记录会抛出错误

什么是Erlang中的模式匹配

你如何在 Haskell 中使用模式匹配和元组列表?