当模式匹配映射到Erlang时,为什么这个变量没有绑定?

Mar*_*len 5 erlang maps pattern-matching

-module(count).
-export([count/1]).

count(L) when is_list(L) ->
  do_count(L, #{});
count(_) ->
  error(badarg).

do_count([], Acc) -> Acc;
do_count([H|T], #{}) -> do_count(T, #{ H => 1 });
do_count([H|T], Acc = #{ H := C }) -> do_count(T, Acc#{ H := C + 1});
do_count([H|T], Acc) -> do_count(T, Acc#{ H => 1 }).
Run Code Online (Sandbox Code Playgroud)

在此示例中,映射键"H"存在且具有与之关联的计数的第三个子句将无法编译.编译器抱怨:

count.erl:11: variable 'H' is unbound    
Run Code Online (Sandbox Code Playgroud)

为何H不受约束?

这顺便说一下:

do_count([], Acc) -> Acc;
do_count([H|T], Acc) -> do_count(T, maps:update_with(H, fun(C) -> C + 1 end, 1, Acc)).
Run Code Online (Sandbox Code Playgroud)

但似乎模式匹配应该起作用,而事实并非如此.

Ric*_*rdC 10

答案与我最近给出的答案几乎相同:https: //stackoverflow.com/a/46268109/240949.

在模式中多次使用同一个变量时,在这种情况下与H一样:

do_count([H|T], Acc = #{ H := C }) -> ...
Run Code Online (Sandbox Code Playgroud)

Erlang中模式匹配的语义说这就像你写的一样

do_count([H|T], Acc = #{ H1 := C }) when H1 =:= H -> ...
Run Code Online (Sandbox Code Playgroud)

也就是说,它们首先分开绑定,然后进行相等性比较.但是需要知道地图模式中的关键字 - 它不能是像H1这样的变量,因此错误(与我链接的答案中的二进制模式中的字段大小说明符完全相同).

这个问题的主要区别在于你有一个带有两个独立参数的函数头,你可能认为模式[H | T]应该先匹配,在第二个模式尝试之前绑定H,但是没有这样的排序保证; 就像你使用了一个带有元组模式{[H | T],#{H:= C}}的参数一样.