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 }).
这是来自 "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 }).