Search code examples
erlangets

Can multiple guards be used in an erlang ets match spec?


I would like to construct a match spec to select the first element from a tuple when a match is found on the second element, or the second element when the first element matches. Rather than calling ets:match twice, can this be done in one match specification?


Solution

  • Yes.

    In documentation there is example of is_integer(X), is_integer(Y), X + Y < 4711, or [{is_integer, '$1'}, {is_integer, '$2'}, {'<', {'+', '$1', '$2'}, 4711}].

    If you are using fun2ms just write funciton with two clauses.

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

    But you could also create two MatchFunctions. Each consist {MatchHead, [Guard], Return}.

    Match head basically tells you how your data looks (is it a tuple, how many elements ...) and assigns to each element match variable $N where N will be some number. Lets say are using two-element tuples, so your match head would be {'$1', '$2'}.

    Now lets create guards: For first function we will assume something simple, like first argument is integer greater than 10. So first guard will be {is_integer, '$2'}, and second {'>', '$2', 5}. In both we use firs element of our match head '$2'. Second match function would have same guards, but with use of '$1'.

    And at last the return. Since we would like to just return one element, for first function it will be '$1', and for second '$2' (returning tuple is little more complicated, since you would have to wrap it in additional on-element tuple).

    So finally, when put together it gives us

    [ _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
    

    Havent had too much time to test it all, but it should work (maybe with minor tweaks).