5

我正在阅读《用 Erlang 思考》一书。在“图 10:案例示例”中,它具有以下示例:

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

它说 :

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

但如果我真的匹配 [ _One, _Two | _Tail ] 一切仍然按预期工作。书里有错误还是我有什么问题?

4

2 回答 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 会依次与所有模式匹配。并且这种顺序是有保证的。被many返回是因为首先[a,b]匹配[_One, _Two | _Tail],并且_Tail[](一个空列表)。

因此,即使[ _One, _Two | _Tail ]在您的情况下可行,使用[ _One, _Two , _Three | _Tail ]也被认为是一种很好的做法,以防您之后切换模式。

于 2012-06-04T22:00:56.913 回答
2

这是书中的“错误”。我认为他们忘记了之前匹配的两个元素。但是,匹配规则尽可能具体,有利于维护,所以如果要匹配“三个或更多元素”,请具体说明并按照书中的内容进行操作。将来有人可能会删除以前的规则,或者出于任何原因重新排序。

于 2012-06-04T16:22:19.297 回答