Соответствие кортежей с небезразличными переменными в Erlang - PullRequest
6 голосов
/ 03 августа 2011

Я ищу способ найти кортежи в списке в Erlang, используя частичный кортеж, аналогично функторам, совпадающим в Прологе.Например, я хотел бы, чтобы следующий код возвращал true:

member({pos, _, _}, [..., {pos, 1, 2}, ...])

Этот код не работает сразу из-за следующей ошибки:

variable '_' is unbound

Есть краткоеспособ добиться того же эффекта?

Ответы [ 6 ]

4 голосов
/ 03 августа 2011

Для простых случаев лучше использовать уже упомянутые списки : keymember / 3 . Но если вам действительно нужна функция member, вы можете реализовать ее самостоятельно так:

member(_, []) ->
    false;
member(Pred, [E | List]) ->
    case Pred(E) of
        true ->
            true;
        false ->
            member(Pred, List)
    end.

Пример:

>>> member(fun ({pos, _, 2}) -> true; (_) -> false end, [..., {pos, 1, 2}, ...]).
3 голосов
/ 03 августа 2011

Используйте списки: ключевой член / 3 вместо.

2 голосов
/ 05 августа 2011

Вы можете сделать это с помощью макроса, используя понимание списка:

-define(member(A,B), length([0 || A <- B])>0).

?member({pos, _, _}, [{width, 17, 42}, {pos, 1, 2}, totally_irrelevant]).

Это не очень эффективно (проходит через весь список), но это наиболее близкий к исходному синтаксису.

Если вы хотите фактически извлечь элементы, которые вам соответствуют, просто удалите 'length' и добавьте переменную:

-define(filter(A,B), [_E || A =_E <- B]).
0 голосов
/ 06 сентября 2012

Может использовать ets:match:

6> ets:match(T, '$1'). % Matches every object in the table
[[{rufsen,dog,7}],[{brunte,horse,5}],[{ludde,dog,5}]]
7> ets:match(T, {'_',dog,'$1'}).
[[7],[5]]
8> ets:match(T, {'_',cow,'$1'}).
[]
0 голосов
/ 04 августа 2011

Другой возможностью было бы сделать то, что делают спецификации соответствия, и использовать атом '_' вместо необработанного _.Затем вы могли бы написать функцию, подобную следующей:

member(X, List) when is_tuple(X), is_list(List) ->
    member2(X, List).

% non-exported helper functions:

member2(_, []) ->
    false;
member2(X, [H|T]) when not is_tuple(H); size(X) =/= size(H) ->
    member2(X, T);
member2(X, [H|T]) ->
    case is_match(tuple_to_list(X), tuple_to_list(H)) of
        true -> true;
        false -> member2(X, T)
    end.

is_match([], []) ->
    true;
is_match(['_'|T1], [_|T2]) ->
    is_match(T1, T2);
is_match([H|T1], [H|T2]) ->
    is_match(T1, T2);
is_match(_, _) ->
    false.

Тогда ваш вызов теперь будет выглядеть так:

member({pos, '_', '_'}, [..., {pos, 1, 2}, ...])

Это не позволит вам сопоставить шаблоны, такие как {A, A, '_'}(проверка, где первые два элемента идентичны), но если вам не нужны переменные, это должно сработать.

Вы также можете расширить его, чтобы использовать переменные, используя аналогичный синтаксис для соответствия спецификациям ('$1', '$2' и т. Д.) Немного больше работы - добавьте третий параметр в is_match с привязками переменных, которые вы видели до этого, затем напишите для них предложения функций, аналогичные предложению для '_'.

Конечно, это не самый быстрый метод.С предупреждением, которое я на самом деле не измерял, я ожидаю, что использование сопоставления с шаблоном в языке с использованием веселья даст гораздо лучшую производительность, хотя и делает сайт вызовов немного более многословным.Это компромисс, который вы должны рассмотреть.

0 голосов
/ 03 августа 2011

Вы можете сделать это, используя понимание списка:

Matches = [ Match || {Prefix, _, _} = Match <- ZeList, Prefix == pos].

...