Current section
Files
Jump to
Current section
Files
src/fn.erl
-module(fn).
-export([ compose/1, compose/2
, naive/2
, error_monad/2
, partial/2
]).
%%
%% Function composition
%%
%% Fn = fn:compose(fun(X) -> X + X end, fun(X) -> X * 4 end)
%% Fn(10) % => 80
%% Fn(12) % => 96
%%
compose(F, G) ->
fun(X) ->
F(G(X))
end.
%%
%% Multiple function composition
%%
%% Fn = fn:compose(
%% [ fun(X) -> X + 3 end
%% , fun(X) -> X * 4 end
%% , fun(X) -> X - 2 end
%% ])
%% Fn(10) % => 50
%% Fn(13) % => 62
%%
compose([]) ->
undefined;
compose(Fns) ->
compose_acc(Fns, fun(X) -> X end).
compose_acc([], Acc) ->
Acc;
compose_acc([Fn | T], Acc) ->
compose_acc(T, compose(Fn, Acc)).
%%
%% Naive application
%%
%% Val = fn:naive(
%% [ fun(X) -> X + 3 end
%% , fun(X) -> X * 4 end
%% , fun(X) -> X - 2 end
%% ], 10),
%% Val % => 50
%%
naive([], Arg) ->
Arg;
naive([Fun | Funs], Arg) ->
naive(Funs, Fun(Arg)).
%%
%% Error monad application
%%
%% Val1 = fn:error_monad(
%% [ fun(X) -> {ok, X + 3} end
%% , fun(X) -> {ok, X * 4} end
%% , fun(X) -> {ok, X - 2} end
%% ], 10),
%% Val1 % => {ok, 50}
%%
%% Val2 = fn:error_monad(
%% [ fun(X) -> {ok, X + 3} end
%% , fun(X) -> {ok, X * 4} end
%% , fun(_) -> {error, something_went_wrong} end
%% ], 10),
%% Val2 % => {error, something_went_wrong}
%%
error_monad([], Arg) ->
{ok, Arg};
error_monad([Fun | Funs], Arg) ->
case Fun(Arg) of
{ok, V} ->
error_monad(Funs, V);
{error, E} ->
{error, E}
end.
%%
%% Partial application
%%
%% Fn1 = fn:partial(fun lists:map/2, [fun erlang:list_to_atom/1])
%% Fn1(["test", "partial"]) % => [test, partial]
%%
%% Fn2 = fn:partial(fun lists:foldl/3, [fun(X, Acc) -> X * Acc end, 1])
%% Fn2([2, 5, 10]) % => 100
%%
partial(F, FixedArgs) ->
{arity, Arity} = erlang:fun_info(F, arity),
case length(FixedArgs) of
L when L < Arity ->
Args = [{var, 1, N} ||
N <- lists:seq(1, Arity - L)],
FArgs = [case is_function(A) of
false -> erl_parse:abstract(A);
true -> {var, 1, erlang:fun_to_list(A)}
end || A <- FixedArgs],
Parsed = [{'fun', 1,
{clauses,
[{clause, 1, Args, [],
[{call, 1,
{var, 1, 'F'},
FArgs ++ Args}]}]}}],
Binds = [{erlang:fun_to_list(A), A} ||
A <- FixedArgs, is_function(A)],
{_, R, _} = erl_eval:exprs(Parsed, [{'F', F}] ++ Binds),
R
end.