illegal pattern in map of Erlang
@EWit, Felipe Mafra:
maps does just what it is supposed to do; what's missing here is the reduce part:
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.
Quoted from OTP 17.0 Release Notes:
OTP-11616 == erts stdlib hipe dialyzer compiler 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.
Currently you can use maps
module to implement 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.
The answers from IRC (#erlang@freenode):
- variables as keys in matches are not supported yet (release 17.0)
- A more general issue affects matching arguments of a function: line 7's
H
is matched 2 times; or once and used to match N then. (This issue also appears with binaries)
This should be solved in the coming releases.
As of release 17 this works:
-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.
Here is another version (only tested on 18) that is slightly more similar to the one in the book:
-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.
When you want to match a map, you need like this:
#{key1 := Pattern1, key2 := Pattern2, ...} = VarContainingAMap.
you can read the document: https://joearms.github.io/published/2014-02-01-big-changes-to-erlang.html