【问题标题】:String function clause matching字符串函数子句匹配
【发布时间】:2021-03-07 15:48:50
【问题描述】:

我在为旧的 Advent of Code 任务编写一些简单的 erlang 代码时遇到了问题。

下面的程序应该读取行,按出现次数对字符串中的字符进行分组,然后计算重复三个字符的行数。


count_occurrences([], Map) -> Map;
count_occurrences([H | T], Map) ->
    count_occurrences(T, maps:put(H, maps:get(H, Map, 0) + 1, Map)).

count(Line, Count) ->
    Map = count_occurrences(Line, #{}),
    case lists:member(3, maps:values(Map)) of
        true -> Count + 1;
        false -> Count
    end.

run() ->
    {ok, Binary} = file:read_file("data.txt"),
    Lines = binary:split(Binary, <<"\n">>, [global]),
    Result = lists:foldl(fun count/2, 0, Lines),
    Result.

但是,我收到以下错误消息:

10> c(day2).   
{ok,day2}
11> day2:run().
** exception error: no function clause matching day2:count_occurrences(<<"bpacnmelhhzpygfsjoxtvkwuor">>,#{}) (day2.erl, line 5)
     in function  day2:count/2 (day2.erl, line 10)
     in call from lists:foldl/3 (lists.erl, line 1263)

我不明白为什么&lt;&lt;"bpacnmelhhzpygfsjoxtvkwuor"&gt;&gt;,#{} 与第二个“count_occurrences”函数子句不匹配——字符串与列表相同,对吧?为什么不匹配 [H | T]?

【问题讨论】:

    标签: erlang


    【解决方案1】:

    请注意,您也可以通过语法稍有不同的二进制文件进行迭代:

    count_occurrences(<<>>, Map) -> Map;
    count_occurrences(<<H, T/binary>>, Map) ->
        count_occurrences(T, maps:put(H, maps:get(H, Map, 0) + 1, Map)).
    

    默认情况下,H 被假定为一个字节,但您可以添加修饰符来指定要选择的位数等等。请参阅documentation for the Bit Syntax。

    【讨论】:

      【解决方案2】:

      看看这个例子:

      -module(a).
      -compile(export_all).
      
      go([_H|_T], _X) ->
          "First arg was a list";
      go("a", _X) ->
          "First arg was a string";
      go(<<"a">>, _X) -> 
          "First arg was a binary".
      

      在外壳中:

      5> a:go(<<"a">>, #{a=>1, b=>2}).
      "First arg was a binary"
      

      和:

      6> a:go("a", #{a=>1, b=>2}).    
      "First arg was a list"
      

      字符串和列表一样,对吧?

      是的,双引号字符串是创建整数列表的快捷方式,其中列表中的整数是字符的 ascii 代码。因此,上面的第二个函数子句永远不会匹配:

      a.erl:6:警告:此子句无法匹配,因为前一个子句 第 4 行总是匹配

      但是....二进制文件,例如&lt;&lt;"abc"&gt;&gt; 不是字符串,因此二进制文件不是创建整数列表的快捷方式。

      8> "a" =:= [97].
      true
      

      好的,你知道的。但是,现在:

      9> "a" =:= <<"a">>.
      false
      
      10> <<"a">> =:= <<97>>.
      true
      
      11> "a" =:= <<97>>.
      false
      

      最后:

      13> <<"abc">> =:= <<97, 98, 99>>.
      true
      

      最后一个例子表明,在二进制文件中指定双引号字符串只是在二进制文件中指定逗号分隔的整数列表的快捷方式——但是在二进制文件中指定双引号字符串并不能以某种方式将二进制文件转换为列表。

      【讨论】:

      • 谢谢,真正的困惑原来是字符串和二进制之间的区别。这解决了我的问题。
      【解决方案3】:

      你得到这个错误因为函数 count_occurrences/2 期望第一个参数 list - [&lt;&lt;"bpacnmelhhzpygfsjoxtvkwuor"&gt;&gt;] 或 "bpacnmelhhzpygfsjoxtvkwuor" 但被放入 binary - &lt;&lt;"bpacnmelhhzpygfsjoxtvkwuor"&gt;&gt;。在第 10 行的模块 day2.erl 的函数 count/2 中仔细检查输入数据 Line:

      1> is_list([]).
      true
      2> is_list("").
      true
      3> is_list(<<"">>).
      false
      4> is_list(binary_to_list(<<"">>)).
      true
      

      【讨论】:

        猜你喜欢
        • 2018-07-16
        • 1970-01-01
        • 1970-01-01
        • 2019-12-24
        • 1970-01-01
        • 1970-01-01
        • 2018-05-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多