【问题标题】:illegal pattern in map of ErlangErlang地图中的非法模式
【发布时间】:2014-05-31 03:42:57
【问题描述】:

代码如下:

-module(map_demo).
-export([count_characters/1]).

count_characters(Str) ->
count_characters(Str, #{}).

count_characters([H|T], #{ H => N } = X) ->
    count_characters(T, X#{ H := N+1 });
count_characters([H|T], X) ->
    count_characters(T, X#{ H => 1});
count_characters([], X) ->
    X.

在Erlang shell中编译代码时,报如下错误:

1> c(map_demo).
map_demo.erl:7: illegal pattern
map_demo.erl:8: variable 'N' is unbound
map_demo.erl:10: illegal use of variable 'H' in map
map_demo.erl:7: Warning: variable 'H' is unused
error

我是 Erlang 的新手,我自己找不到任何问题。如何纠正?

【问题讨论】:

  • 我能找到的最接近的事情是这是一个“已知错误”。这些二郎人是认真的吗?在这种情况下,这是一个巨大的错误!我认为这是您从 Joe Armstrong 本人的“Programming Erlang”中学到的东西,我对这不起作用的核心感到震惊!
  • 从 Erlang/OTP 18.0 开始,此代码“仅”在第 7、8 行抛出错误,因为绑定变量在地图中使用是合法的:__________________________________________________________________ 1> K = thecake, #{K => isalie}. _______________________________________________ #{thecake => isalie}
  • 运行版本 20,这仍然是一个错误?!也许我会在生气之前多研究一下,但是……stackoverflow.com/questions/44247735/…
  • @alexakarpov 不,错误(已接受答案中的第 1 点)已在 R18 中修复,并且仍然存在的问题(第 2 点)不是错误。或者更确切地说,这是书中的错误,而不是 Erlang。

标签: map erlang


【解决方案1】:

来自 IRC (#erlang@freenode) 的答案:

  1. 尚不支持将变量作为匹配项中的键(17.0 版)
  2. 一个更普遍的问题会影响函数的匹配参数:第 7 行的 H 匹配了 2 次;或一次,然后用于匹配 N。 (此问题也出现在二进制文件中)

这应该在即将发布的版本中解决。

截至第 17 版 this 有效:

-module(count_chars).
-export([count_characters/1]).

count_characters(Str) ->
        count_characters(Str, #{}).

%% maps module functions cannot be used as guards (release 17)
%% or you'll get "illegal guard expression" error
count_characters([H|T], X) ->
    case maps:is_key(H,X) of
        false -> count_characters(T, maps:put(H,1,X));
        true  -> Count = maps:get(H,X),
                         count_characters(T, maps:update(H,Count+1,X))
    end;
count_characters([], X) ->
        X.

这是另一个版本(仅在 18 上测试过),它与书中的版本稍微相似:

-module(count_chars).
-export([count_characters/1]).

count_characters(Str) ->
        count_characters(Str, #{}).

count_characters([H|T], X) ->
    case maps:is_key(H,X) of
        false -> count_characters(T, X#{ H => 1 });
        true  -> #{ H := Count } = X,
                 count_characters(T, X#{ H := Count+1 })
    end;
count_characters([], X) ->
        X.

【讨论】:

  • 既然 (1) 就是这种情况,那么在 17.0 中使用地图编写此代码的正确方法是什么?
【解决方案2】:

引用自OTP 17.0 Release Notes

OTP-11616 == erts stdlib hipe 透析器编译器 typer ==

    EEP43: New data type - Maps

    With Maps you may for instance:

    -- M0 = #{ a => 1, b => 2}, % create associations

    -- M1 = M0#{ a := 10 }, % update values

    -- M2 = M1#{ "hi" => "hello"}, % add new associations

    -- #{ "hi" := V1, a := V2, b := V3} = M2. % match keys with
    values

    For information on how to use Maps please see the Reference
    Manual.

    The current implementation is without the following features:

    -- No variable keys

    -- No single value access

    -- No map comprehensions

    Note that Maps is experimental during OTP 17.0.

目前可以使用maps模块实现count_characters

count_characters(Str) ->
    count_characters(Str, #{}).

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

【讨论】:

    【解决方案3】:

    @EWit,费利佩·马夫拉:

    maps 做的正是它应该做的;这里缺少的是 reduce 部分:

    count(Str) -> M = count_chars(Str, maps:new()), % maps part, bad naming
        L = maps:to_list(M),                        % to be able to sum
        N = [X || {_,X} <- L],                      % strip the numbers
        lists:sum(N).                               % sum them up
    
    count_chars([H|T], Map) when is_map(Map)->
        N = maps:get(H, Map, 0),
        count_chars(T, maps:put(H, N + 1, Map));
    count_chars([], Map) -> Map.
    

    【讨论】:

      【解决方案4】:

      当你想匹配一张地图时,你需要这样:

      #{key1 := Pattern1, key2 := Pattern2, ...} = VarContainingAMap.
      

      您可以阅读文档: https://joearms.github.io/published/2014-02-01-big-changes-to-erlang.html

      【讨论】:

        【解决方案5】:

        匹配语法问题。

        Fof 匹配使用:=。示例

        test(#{ key := Test }) -> Test.

        对于关联的键和值,请使用=&gt;。例子: M = #{ keynew =&gt; 123 }

        【讨论】:

        • 那么,如何更正代码呢?我刚试过你的方法。但它不起作用。
        • 抱歉,我跳过了一会儿。如果你使用map,key是不可变的,需要使用#{ key => Value }。
        【解决方案6】:

        我猜您使用的是 R17,因为此功能仅在此版本中可用。

        看一些文档,我的理解是你应该这样写代码(我无法测试它,我仍在使用 R15 :o)

        -module(map_demo).
        -export([count_characters/1]).
        
        count_characters(Str) ->
        count_characters(Str, #{}).
        
        count_characters([H|T], #{ H := N } = X) ->
            count_characters(T, X#{ H := N+1 });
        count_characters([H|T], X) ->
            count_characters(T, X#{ H => 1});
        count_characters([], X) ->
            X.
        

        【讨论】:

          【解决方案7】:

          -模块(count_chars)。

          %% API

          -export([count/1]).

          count(Str) -> count_chars(Str, maps:new()).

          count_chars([H|T], Map) when is_map(Map)->

          N = maps:get(H, Map, 0),
          count_chars(T, maps:put(H, N + 1, Map));
          

          count_chars([], Map) -> 地图。

          【讨论】:

          • 请详细说明为使此答案正常运行所做的更改。仅仅提供代码并不能帮助首先澄清问题所在。
          猜你喜欢
          • 2015-07-25
          • 1970-01-01
          • 2023-03-28
          • 2016-03-10
          • 2020-04-09
          • 1970-01-01
          • 2015-04-11
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多