Подтвердить что ты не робот

Незаконный узор на карте Эрланг

Код ниже:

-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 и просто не могу найти что-то не так. Как его исправить?

4b9b3361

Ответ 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.

Ответ 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 ([], Карта) → Карта.