Erlang,特定地图键上的模式匹配?
Posted
技术标签:
【中文标题】Erlang,特定地图键上的模式匹配?【英文标题】:Erlang, pattern matching on a particular map's key? 【发布时间】:2020-04-09 22:43:21 【问题描述】:这是“用 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).
..它无情地产生以下错误:
变量“C”未绑定
所以我有点卡在这里;在我看来,变量 'C' 是绑定的,即它必须是字符串的头部(只是一个字符的链接列表,对吗?)。然而 Erlang 不同意我的观点,它打破了我现在正在阅读的(可能是过时的?)书中的例子。
那怎么了?在这个特定示例中,模式匹配的正确方法是什么?
附:书中的截图。注意稍微不同的语法,这对我也不起作用:
附言我正在使用从官方网站下载的最新版本的 Erlang。
【问题讨论】:
模式匹配不适用于带有变量的地图,请参阅***.com/a/34810812/1030675 和***.com/a/59148351/1030675。 这本书包含了很多关于地图应该如何在 erlang 中工作的一厢情愿。因此,我发现这本书的那一部分非常令人沮丧。如果我没记错的话,解释是模式匹配的顺序是未知的,当你写[C|Substring], #C := N=Result
时,你假设模式[C|Substring]
将首先匹配,所以C被绑定在第二个模式中.但是,如果模式以相反的顺序匹配,则 C 将在映射模式中未绑定,因此会出现错误消息。
答案是:link to another SO answer。
#C := N=Result
不适用于引入地图数据结构的 OTP 的第一个版本,但现在可以使用。
【参考方案1】:
C
必须在计算表达式 #C := N=Result
之前绑定。
您认为C
是绑定的,因为第一个参数[C|Substring]
之前已评估:#C := N=Result
。事实上并非如此。在头部评估成功并且函数进入主体之前,没有真正的分配。
写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 ).
【讨论】:
以上是关于Erlang,特定地图键上的模式匹配?的主要内容,如果未能解决你的问题,请参考以下文章