Erlang generate anonymous function of an arbitary arity? - erlang

Is it possible to write a function that returns an anonymous function of a specified arity? I'd like to be able to generate a function that can be passed to meck:expect/3 as the third argument so I can dynamically mock existing functions of any arity?
I've done quite a bit of searching and it seems like the only way to solve this is by hardcoding things like this:
gen_fun(1, Function) ->
fun(A) -> Function([A]) end;
gen_fun(2, Function) ->
fun(A, B) -> Function([A, B]) end;
...

It's not pretty, but you can use the same trick as the shell and build your functions from the ground up:
-module(funny).
-export([gen_fun/1, gen_fun/2]).
-spec gen_fun(function()) -> function().
gen_fun(Function) ->
{arity, Arity} = erlang:fun_info(Function, arity),
gen_fun(Arity, Function).
-spec gen_fun(non_neg_integer(), function()) -> function().
gen_fun(Arity, Function) ->
Params = [{var, 1, list_to_atom([$X| integer_to_list(I)])} || I <- lists:seq(1, Arity)],
Anno = erl_anno:new(1),
Expr =
{'fun',
Anno,
{clauses, [{clause, Anno, Params, [], [{call, Anno, {var, Anno, 'Function'}, Params}]}]}},
{value, Fun, _Vars} = erl_eval:expr(Expr, [{'Function', Function}]),
Fun.
Then, in the shell…
1> F = funny:gen_fun(fun io:format/2).
#Fun<erl_eval.43.40011524>
2> F("~ts~n", ["πŸ˜‘"]).
πŸ˜‘
ok
3> F1 = funny:gen_fun(fun io:format/1).
#Fun<erl_eval.44.40011524>
4> F1("πŸ˜‘~n").
πŸ˜‘
ok
5>

Related

Is there a way to tell whether a function has a matching clause without calling it in Erlang?

E.g. suppose I have a module named caller, and one of the functions defined therein contains this expression:
Callee:some_function(foo, Bar)
caller could try to catch function_clause, but how would caller know that it comes directly from Callee:some_function as opposed to some other function call (e.g. a call that Callee:some_function itself makes)?
You could catch function_clause errors with try-catch, and check if the stacktrace matches:
-module(foo).
-compile(export_all).
maybe_apply(Mod, Fun, Args) ->
try apply(Mod, Fun, Args)
catch
error:function_clause ->
case erlang:get_stacktrace() of
[{Mod, Fun, Args} | _] ->
{error, function_clause};
[{Mod, Fun, Args, _LineNumber} | _] ->
{error, function_clause};
Stacktrace ->
{error, other_function_clause, Stacktrace}
end
end.
Here is an example that shows how it distinguishes between a function clause error in lists:filter itself, and a function clause in a function called by lists:filter:
> foo:maybe_apply(lists, filter, [x, [1,2,3]]).
{error,function_clause}
> foo:maybe_apply(lists, filter, [fun(x) -> true end, [1,2,3]]).
{error,other_function_clause,
[{erl_eval,'-inside-an-interpreted-fun-',[1],[]},
{erl_eval,expr,3,[]}]}
You can use catch (callee:some_function(foo, Bar)) and analyse the error message if any:
1> catch (lists:filter(5,[1,2,3])).
{'EXIT',{function_clause,[{lists,filter,
[5,[1,2,3]],
[{file,"lists.erl"},{line,1283}]},
{erl_eval,do_apply,6,
[{file,"erl_eval.erl"},{line,661}]},
{erl_eval,expr,5,[{file,"erl_eval.erl"},{line,434}]},
{shell,exprs,7,[{file,"shell.erl"},{line,684}]},
{shell,eval_exprs,7,[{file,"shell.erl"},{line,639}]},
{shell,eval_loop,3,
[{file,"shell.erl"},{line,624}]}]}}
2> catch(lists:map(fun ({X,Y}) -> X + Y end, [{1,2},{3,4}])).
[3,7]
3> catch(lists:map(fun ({X,Y}) -> X + Y end, [{1,2},{3,4,5}])).
{'EXIT',{function_clause,[{erl_eval,'-inside-an-interpreted-fun-',
[{3,4,5}],
[]},
{erl_eval,expr,3,[]}]}}
4>
4> catch(lists:map(fun ({X,Y}) -> X / Y end, [{1,2},{3,0}])).
{'EXIT',{badarith,[{erlang,'/',[3,0],[]},
{lists,map,2,[{file,"lists.erl"},{line,1237}]},
{lists,map,2,[{file,"lists.erl"},{line,1237}]},
{erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,661}]},
{erl_eval,expr,5,[{file,"erl_eval.erl"},{line,434}]},
{shell,exprs,7,[{file,"shell.erl"},{line,684}]},
{shell,eval_exprs,7,[{file,"shell.erl"},{line,639}]},
{shell,eval_loop,3,[{file,"shell.erl"},{line,624}]}]}}
5>
you can recognize the case that you are looking for because it has the form:
{'EXIT',{function_clause,[{callee,some_function,
[foo, Bar],
[{file,"callee.erl"},{line,LineNumber}]}|Stack]}}

Erlang - Searching for tuples within tuples

Using Erlang, I have the following expression:
{add,{var,a},{mul,{num,2},{var,b}}}
and I am using lists:keymember to see whether the letter b is within the expression as such:
lists:keymember(b,2,[expr])
However, it doesn't look within the third tuple '{mul,{num,2},{var,b}' as that is a separate tuple. Is there a function that will search through the whole tuple and tuples within?
Thanks
As far I as I know there are no such functions. Probably you will have to implement some custom solution using recursion. Here is my example:
-module(test).
-compile(export_all).
find(_, []) -> false;
find(E, T) when is_tuple(T) ->
find(E, tuple_to_list(T));
find(E, [H|T]) ->
case find(E, H) of
false -> find(E, T);
true -> true
end;
find(V, E) -> V == E.
And usage:
1> test:find(b, {add,{var,a},{mul,{num,2},{var,b}}}).
true
2> test:find(b, {add,{var,a},{mul,{num,2},{var,c}}}).
false
Please review your code.
Line1: this is a tree, not a list.
Line2: expr is not a variable.
What you want to do is a visitor function, and you'll have to write it yourself.
A very good start would be to read this.

Racket ormap in erlang

Is there a better way to implement Racket's ormap in Erlang than:
ormap(_, []) -> false;
ormap(Pred, [H|T]) ->
case Pred(H) of
false -> ormap(Pred, T);
_ -> {ok, Pred(H)}
end.
Looks pretty good to me. I'm not sure how smart Erlang is about optimizing these things, but you might want to actually bind the non-false pattern match to a variable, and avoid recomputing Pred(H).
ormap(_, []) -> false;
ormap(Pred, [H|T]) ->
case Pred(H) of
false -> ormap(Pred, T);
V -> {ok, V}
end.
The Racket version doesn't include the ok symbol, but that seems like the Erlangy thing to do so I don't see anything wrong with it. You might similarly expect Pred to return an attached ok symbol for the non-false case, in which case:
V -> V
or
{ok, V} -> {ok, V}
should work.

Matching tuples with don't-care variables in Erlang

I am looking for a way to find tuples in a list in Erlang using a partial tuple, similarly to functors matching in Prolog. For example, I would like to following code to return true:
member({pos, _, _}, [..., {pos, 1, 2}, ...])
This code does not work right away because of the following error:
variable '_' is unbound
Is there a brief way to achieve the same effect?
For simple cases it's better to use already mentioned lists:keymember/3. But if you really need member function you can implement it yourself like this:
member(_, []) ->
false;
member(Pred, [E | List]) ->
case Pred(E) of
true ->
true;
false ->
member(Pred, List)
end.
Example:
>>> member(fun ({pos, _, 2}) -> true; (_) -> false end, [..., {pos, 1, 2}, ...]).
Use lists:keymember/3 instead.
You can do it with a macro using a list comprehension:
-define(member(A,B), length([0 || A <- B])>0).
?member({pos, _, _}, [{width, 17, 42}, {pos, 1, 2}, totally_irrelevant]).
It is not very efficient (it runs through the whole list) but it is the closest I can think to the original syntax.
If you want to actually extract the elements that match you just remove 'length' and add a variable:
-define(filter(A,B), [_E || A =_E <- B]).
You could do it using list comprehension:
Matches = [ Match || {Prefix, _, _} = Match <- ZeList, Prefix == pos].
Another possibility would be to do what match specs do and use the atom '_' instead of a raw _. Then, you could write a function similar to the following:
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.
Then, your call would now be:
member({pos, '_', '_'}, [..., {pos, 1, 2}, ...])
This wouldn't let you match patterns like {A, A, '_'} (checking where the first two elements are identical), but if you don't need variables this should work.
You could also extend it to use variables using a similar syntax to match specs ('$1', '$2', etc) with a bit more work -- add a third parameter to is_match with the variable bindings you've seen so far, then write function clauses for them similar to the clause for '_'.
Granted, this won't be the fastest method. With the caveat that I haven't actually measured, I expect using the pattern matching in the language using a fun will give much better performance, although it does make the call site a bit more verbose. It's a trade-off you'll have to consider.
May use 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'}).
[]

Erlang - Anonymouos Function

If i call the test(), it doesnt work. Can someone explain this ?.
-module(anony).
-export([test/0, test1/0]).
test1() -> "hello".
test() ->
C = fun(F) -> Val = F(), io:format("~p ", [Val]) end,
lists:foreach(debug, [test1]).
test1 on its own is simply an atom, not a reference to the local function. To create a reference to the function use fun Function/Arity as below.
-module(anony).
-export([test/0, test1/0]).
test1() -> "hello".
test() ->
C = fun(F) -> Val = F(), io:format("~p ", [Val]) end,
lists:foreach(C, [fun test1/0]).
You could also construct an anonymous function that calls test1 like this: fun() -> test1() end, but there's no reason to that unless you have additional values you want to pass in or the like.
The other two answers do actually answer the question. I just want to add to them.
I expect that you want to be able to pass an atom and call the function with that name. This is not possible for local functions. It is very possible for exported functions though.
So you can do something like (my only change is to add "?MODULE:", and to change "debug" to "C"):
-module(anony).
-export([test/0, test1/0]).
test1() -> "hello".
test() ->
C = fun(F) -> Val = ?MODULE:F(), io:format("~p ", [Val]) end,
lists:foreach(C, [test1]).
First, C variable hasn't been used at all, and second you should wrap the test1 with a fun/end:
-module(anony).
-export([test/0, test1/0]).
test1() -> "hello".
test() ->
C = fun(F) -> Val = F(), io:format("~p ", [Val]) end,
lists:foreach(C, [fun() -> test1() end]).

Resources