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 或 平等检查 分别像 Prolog 和 Erlang做。这在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 中的模式匹配的主要内容,如果未能解决你的问题,请参考以下文章