在Erlang中使用无关变量匹配元组

时间:2011-08-03 07:57:11

标签: erlang pattern-matching

我正在寻找一种在Erlang中使用部分元组在列表中查找元组的方法,类似于在Prolog中匹配的函子。例如,我想按照代码返回true

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

由于以下错误,此代码无法立即生效:

variable '_' is unbound

是否有一种达到同样效果的简短方法?

6 个答案:

答案 0 :(得分:3)

改为使用lists:keymember/3

答案 1 :(得分:3)

对于简单的情况,最好使用已经提到的lists: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}, ...]).

答案 2 :(得分:2)

您可以使用列表推导使用宏来执行此操作:

-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]).

答案 3 :(得分:0)

你可以使用列表理解来做到这一点:

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

答案 4 :(得分:0)

另一种可能性是做匹配规范,并使用原子'_'而不是原始_。然后,您可以编写类似于以下内容的函数:

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使用到目前为止看到的变量绑定,然后为它们编写类似于'_'的子句的函数子句。

当然,这不是最快的方法。有了我实际没有测量过的警告,我希望在语言中使用模式匹配可以提供更好的性能,尽管它确实使调用站点更加冗长。这是一个你需要考虑的权衡。

答案 5 :(得分:0)

可以使用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'}).
[]