Незаконный узор на карте Эрланг
Код ниже:
-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 сообщается о следующих ошибках:
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 и просто не могу найти что-то не так. Как его исправить?
Ответы
Ответ 1
Ответы IRC (# erlang @freenode):
- переменные как ключи в совпадениях пока не поддерживаются (выпуск 17.0)
- Более общая проблема затрагивает совпадающие аргументы функции: строка 7
H
сопоставляется 2 раза; или один раз и используется для соответствия N тогда. (Эта проблема также появляется с двоичными файлами)
Это должно быть разрешено в следующих выпусках.
Начиная с версии 17 это работает:
-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.
Ответ 2
Цитата из OTP 17.0 Примечания к выпуску:
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.
В настоящее время вы можете использовать модуль 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, Фелипе Мафра:
Карты делают то, что он должен делать; недостающая здесь часть сокращения:
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.
вы можете прочитать "ducoment":
http://joearms.github.io/2014/02/01/big-changes-to-erlang.html
Ответ 5
Проблема в синтаксисе соответствия.
Для сопоставления используйте :=
. Пример
test(#{ key := Test }) ->
Test.
И для связанного ключа и значения используйте =>
. Пример:
M = #{ keynew => 123 }
Ответ 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 ([число/1]).
count (Str) → count_chars (Str, maps: new()).
count_chars ([H | T], Карта), когда is_map (Карта) →
N = maps:get(H, Map, 0),
count_chars(T, maps:put(H, N + 1, Map));
count_chars ([], Карта) → Карта.