可以在erlang ets匹配规范中使用多个警卫吗?

时间:2014-11-18 23:04:05

标签: erlang ets

我想构造一个匹配规范,以便在第二个元素上找到匹配时从元组中选择第一个元素,或者在第一个元素匹配时选择第二个元素。而不是调用ets:match两次,这可以在一个匹配规范中完成吗?

2 个答案:

答案 0 :(得分:2)

documentation中有is_integer(X), is_integer(Y), X + Y < 4711[{is_integer, '$1'}, {is_integer, '$2'}, {'<', {'+', '$1', '$2'}, 4711}]的示例。

如果你正在使用fun2ms,只需用两个子句写函数。

fun({X, Y}) when in_integer(X)
                 andalso X > 5 ->
       Y;

   ({X, Y}) when is_integer(Y)
                 andalso Y > 5 ->
       X.

但你也可以创建两个MatchFunctions。每个组成{MatchHead, [Guard], Return}

匹配头基本上会告诉您数据的外观(它是一个元组,有多少元素......)并为每个元素分配匹配变量$N,其中N将是某个数字。让我们说使用两元素元组,所以你的匹配头将是{'$1', '$2'}

现在让我们创建警卫:对于第一个函数,我们将假设一些简单的事情,例如第一个参数是大于10的整数。因此,第一个警卫将是{is_integer, '$2'},第二个{'>', '$2', 5}。在两者中我们使用匹配头'$2'的第一个元素。第二个匹配函数具有相同的保护,但使用'$1'

最后回归。因为我们只想返回一个元素,对于第一个函数,它将是'$1',而对于第二个'$2'(返回元组稍微复杂一点,因为你必须将它包装在另外的元素中元组)。

所以最后,当它放在一起时它给了我们

[ _FirstMatchFunction = {_Head1 = {'$1', '$2'},
                         _Guard1 = [{is_integer, '$2},
                                    {'>', '$2', 5}],     % second element matches
                         _Return1 = [ '$1']},            % return first element             
  _SecondMatchFunction = {_Head2 = {'$1', '$2'},
                          _Guard2 = [{is_integer, '$1},
                                     {'>', '$1', 5}],      % second element matches
                          _Return2 = [ '$2']} ]            % return first element

没有太多时间来测试它,但它应该可以工作(可能需要进行小的调整)。

答案 1 :(得分:0)

-export([main/0]).
-include_lib("stdlib/include/ms_transform.hrl").
main() ->
    ets:new(test, [named_table, set]),
    ets:insert(test, {1, a, 3}),
    ets:insert(test, {b, 2, false}),
    ets:insert(test, {3, 3, true}),
    ets:insert(test, {4, 4, "oops"}),

    io:format("~p~n", [ets:fun2ms(fun({1, Y, _Z}) -> Y;
                     ({X, 2, _Z}) -> X end)]),

    ets:select(test, ets:fun2ms(fun({1, Y, _Z}) -> {first_match, Y};
                   ({X, 2, _Z}) -> {second_match, X}
                end)).

输出结果为:

[{{1,'$1','$2'},[],['$1']},{{'$1',2,'$2'},[],['$1']}]
[{first_match,a},{second_match,b}]