Erlang列表匹配

5
我正在学习Erlang思维这本书。在“图10:case示例”中,它提供了以下示例:
many(X) ->
case X of
    [] ->
        none;
    [ _One ] ->
        one;
    [ _One, _Two ] ->
        two;
    [ _One, _Two , _Three | _Tail ] ->
        many
end.

它说:

如果你想知道为什么第9行没有与[_One,_Two | _Tail]匹配,请查看上一节末尾的列表匹配规则。

但是,如果我实际上与[_One,_Two | _Tail]匹配,一切仍然按预期工作。书中有错误还是我理解有误?
2个回答

10
我觉得这可能不是一个错误。
语义的
[_One, _Two, _Three | _Tail]

这是一个包含三个或更多元素的列表。

该术语的语义

[_One, _Two | _Tail]

这是一个由两个或更多元素组成的列表。

由于第三个模式[ _One, _Two ]已经表示了“由两个元素组成的列表”的情况,所以使用[_One, _Two | _Tail]可能有点多余。

“一切都按预期工作”的原因是有道理的。如果我们将第四个模式放在第三个模式之前,就会得到:

many(X) ->
  case X of
    [] ->
      none;
    [_One] ->
      one;
    [_One, _Two | _Tail] ->  %% Switched
      many;
    [_One, _Two] ->          %% Switched
      two
  end.

那么一切都不会按预期工作。 Mod:many([a,b]) 将返回 many 而不是预期的 two。这是因为在评估“case”表达式时,X依次与所有模式进行匹配。而且这种顺序是有保证的。由于[a,b] 首先与[_One,_Two | _Tail]匹配,其中_Tail[](一个空列表),所以返回了many

因此,即使[_One,_Two | _Tail]在您的情况下可行,但使用[_One,_Two,_Three | _Tail]被认为是一种良好的做法,以防以后需要更改模式。


2

这是书中的一个“错误”。我认为他们忘记了之前匹配两个元素。然而,在匹配规则上尽可能具体是很有维护性的,因此如果你想匹配“三个或更多元素”,请具体说明并按照书中的方法操作。未来有人可能会删除先前的规则,或出于任何原因重新排序它们。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接