Erlang,特定地图键上的模式匹配?

Erlang, pattern matching on a particular map's key?

这是来自 "Programming with Erlang"(第 2 版)的示例:

count_chars([], Result) ->
    Result;
count_chars([C|Substring], #{C := N}=Result) ->
    count_chars(Substring, Result#{C := N+1 });
count_chars([C|Substring], Result) ->
    count_chars(Substring, Result#{C => 1}).

..无情地产生了以下错误:

variable 'C' is unbound

所以我有点被困在这里;在我看来,变量 'C' 是绑定的,即它 必须是 字符串的头部(只是一个字符链表,对吧?)。然而 Erlang 不同意我的看法,打破了我正在阅读的(可能已经过时?)书中的例子。

怎么了?在此特定示例中,模式匹配的正确方法是什么?

P.S。书中截图。注意略有不同的语法,这对我也不起作用:

P.P.S。我正在使用我设法从官方网站下载的最新版本的 Erlang。

C 必须在计算表达式 #{C := N}=Result 之前绑定。

您认为 C 是绑定的,因为第一个参数 [C|Substring] 在之前计算过:#{C := N}=Result。事实上并非如此。在 head 评估成功并且函数进入 body 之前,没有真正的赋值。

count_chars([C|Substring], #{C := N}=Result) ->count_chars([C1|Substring], #{C2 := N}=Result) when C1 =:= C2 ->完全一样

在head求值过程中,每个元素存储在不同的元素(堆中的一个地方),以检查所有参数是否与head定义匹配。在您的情况下,编译器希望将值 C 存储在一个元素中,比方说 x1 和键 C? 在另一个元素中,比方说 x2,然后验证 x1 和 x2 是否相等。如果不对编译器行为进行深入修改,则无法进行第二个操作。

我写了一个小例子来展示它是如何工作的,并用选项'S'编译它,看看编译结果:

test([K|_],K,M) -> % to see how the test of parameter equality is done
     #{K := V} = M, % to verify that this pattern works when K is bound.
     V.

组装结果为:

{function, test, 3, 33}.
  {label,32}.
    {line,[{location,"mod.erl",64}]}.
    {func_info,{atom,mod},{atom,test},3}.
  {label,33}.
    {test,is_nonempty_list,{f,32},[{x,0}]}.               % the whole list is assigned to x0
    {get_hd,{x,0},{x,3}}.                                 % the list's head is assigned to x3
    {test,is_eq_exact,{f,32},[{x,1},{x,3}]}.              % the second parameter K is assigned to x1, verify if x1 =:= x3
    {test,is_map,{f,34},[{x,2}]}.                         % the third parameter M is assigned to x2, check if it is a map if not go to label 34
    {get_map_elements,{f,34},{x,2},{list,[{x,3},{x,0}]}}. % get the value associated to key x3 in the map x2 and store it into x0, if no suck key go to label 34
    return.
  {label,34}.                                             % throw a badmatch error
    {line,[{location,"mod.erl",65}]}.
    {badmatch,{x,2}}.

现在,要编写函数代码,您只需编写:

count_chars([], Result) ->
    Result;
count_chars([C|Substring], Result) ->
    N = maps:get(C, Result, 0) +1,
    count_chars(Substring, Result#{C => N }).