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,特定地图键上的模式匹配?的主要内容,如果未能解决你的问题,请参考以下文章

在cassandra的主键上匹配'like'的模式

为啥 OCaml 模式匹配比 Erlang 弱?

为什么在erlang中对此字符串进行模式匹配会导致尾部的“字符串”和列表的ascii值?

Erlang 模式匹配顺序

什么是 Erlang 中的模式匹配

在erlang中列出尾部模式匹配