我正在完成这本书Thinking in 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]一切仍然按预期工作。书中是否有错误或我出错?
答案 0 :(得分:8)
我认为这可能不是一个错误。
的语义
[_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 ]
也是一种很好的做法,以防您以后切换模式。
答案 1 :(得分:2)
这本书中的“错误”。我认为他们忘记了之前匹配的两个元素。但是,对于维护而言,尽可能使用匹配规则尽可能具体,因此如果要匹配“三个或更多元素”,请具体说明并按照书中的说明进行操作。有人可能会在将来删除以前的规则,或者出于任何原因重新排序它们。