map pattern matching in Erlang, unexpected error (unbound)

回眸只為那壹抹淺笑 提交于 2019-12-11 12:03:41

问题


The code below is basically copied from J.A.'s book:

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

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

count_chars([H|T], #{H := N}=X) -> % line that throws
    count_chars(T, X#{H := N+1});
count_chars([H|T], X) ->
    count_chars(T, X#{H => 1});
count_chars([], X) -> X.

however, compiling it in the shell gives me

151> c(mapz).
mapz.erl:7: variable 'H' is unbound
error
152>

I understand the importance of having H bound before it can be used for matching a key in a map; and, as far as I can tell, it is being matched to the head of the list(string) in the first argument, and is therefore bound by the time the second argument (matching against the map) is evaluated. More to the point, the example being from the book, I suspect it to be correct. The book seems to be using OTP17, however, and I'm now on 20, wonder if things have changed? But which things?

Thank you for your time.


回答1:


in the clause count_chars([H|T], #{H := N}=X) -> ... the compiler does not consider that H has been bound during the pattern matching of the first parameter : [H|T], so it is unable to pattern match the second parameter #{H := N} (I think it could be possible with the actual assembly, see my answer to this topic)

But there is the function you need in the maps library:

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

count_chars([H|T],X) ->
    count_chars(T, maps:update_with(H,fun(V) -> V+1 end, 1,X));
count_chars([], X) ->
    X.

see documentation at Maps erlang doc

even shorter using the lists:foldl/3

count_chars(Str) -> 
    lists:foldl(fun(C,Map) ->  maps:update_with(C,fun(Count) -> Count+1 end, 1,Map) end, #{},Str).



回答2:


You can't do pattern matching (at least not yet) on a Map with a key being a variable, like:

count_chars([H|T], #{H := N}=X)

but this would work:

count_chars([H|T], #{"MyKey" := N}=X)

you can update the code to be like:

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

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

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


来源:https://stackoverflow.com/questions/44247735/map-pattern-matching-in-erlang-unexpected-error-unbound

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!