Search code examples
functional-programmingerlang

How do I map a value from a map to a variable when map is passed in to a function in Erlang?


I have this scenario: Write a function eval/2 that accepts as its first argument a tuple and second argument a map which maps atoms to numbers. For instance,the call eval({add, a, b}, #{a => 1, b => 2})return 3 and the call eval({mul, {add, a, 3}, b}, #{a => 1, b => 2}) return { ok, 8}2. More generally, eval(E, L) accepts as input an expression tuple E of three elements {Op, E1, E2} where Op is add, mul, ’div’ or sub and E1 and E2 is either a number, atom or an expression tuple, and an Erlang map L that acts as lookup table for atoms. The function returns either {ok, Value } or {error, Reason}, where Reason is either variable_not_found if an atom does not exist in the lookup table or unknown_error. Implement the function eval/2 in the module task1 and export it.

example:


1> eval({add, 1, 2}, #{}).
{ok, 3}
2> eval({add, a, b}, #{a=>1}).
{error, variable_not_found}
3> eval({add, {add, a, b}, {add, 1, 2}}, #{a=>2, b=>3}). {ok, 8}


I solved the problem when only a tuple is sent but I don't really know how to handle the map that is sent to the function.

This is my code:

-module(task1).

-export([eval/1, eval/2]).

eval_inner({add, X, Y}) ->
    eval_inner(X) + eval_inner(Y);
eval_inner({mul, X, Y}) ->
    eval_inner(X) * eval_inner(Y);
eval_inner({'div', X, Y}) ->
    eval_inner(X) / eval_inner(Y);
eval_inner({sub, X, Y}) ->
    eval_inner(X) - eval_inner(Y);
eval_inner(X) when is_number(X) ->
    X;
eval_inner(X) when is_atom(X) ->
    maps:get(X, M).

eval(X) ->
    try eval_inner(X) of
        V -> {ok, V}
    catch
        _:_ -> error
    end.

eval(X, M) ->
    

Solution

  • you have to pass the values map around.

    
        -module(task1).
        
        -export([eval/1, eval/2]).
        
        eval_inner({add, X, Y}, M) ->
            eval_inner(X, M) + eval_inner(Y, M);
        eval_inner({mul, X, Y}, M) ->
            eval_inner(X, M) * eval_inner(Y, M);
        eval_inner({'div', X, Y}) ->
            eval_inner(X, M) / eval_inner(Y, M);
        eval_inner({sub, X, Y}) ->
            eval_inner(X, M) - eval_inner(Y, M);
        eval_inner(X, _M) when is_number(X) ->
            X;
        eval_inner(X, M) when is_atom(X) ->
            maps:get(X, M).
        
        eval(X, M) ->
            try eval_inner(X, M) of
                V -> {ok, V}
            catch
                _:_ -> error
            end.