erlz icon indicating copy to clipboard operation
erlz copied to clipboard

Set of helpers functions for more convenient functional programming in Erlang

Overview

Set of helpers functions for more convenient functional programming on Erlang

Provide following ability:

  • currying
  • partial applications
  • simplest monadic computation

Examples

Currying

Fn = fun(A, B, C, D) ->
    A + B + C + D
end,
CFn = erlz:curried(Fn),
10 = (((CFn(1))(2))(3))(4).

Partial application

Fn = fun(A, B, C, D, E) ->
    1 = A,
    2 = B,
    3 = C,
    4 = D,
    5 = E,
    A + B + C + D + E
end,
% Atom '_' is used for specifying place where value must be substituted
PFn = erlz:partial(Fn, [1, '_', '_', 4, 5]),
{arity, 2} = erlang:fun_info(PFn, arity),
15 = PFn(2, 3).

[3,7,1,5] = lists:map(
    erlz:partial(fun lists:nth/2, [3]),
    [
        [1,2,3,4],
        [5,6,7,8],
        [9,0,1,2],
        [3,4,5,6]
    ]).

do-notation

<<"16.0">> = erlz:do(0, [
    fun(X) -> X+1 end,
    fun(X) -> X+3 end,
    % using currying
    (erlz:curried(fun math:pow/2))(2),
    erlz:partial(
        fun erlang:float_to_binary/2,
        ['_', [{decimals, 4}, compact]])
]).

{left,{stop,1}} = erlz:either_do(0, [
    fun(X) -> {right, X+1} end,
    fun(X) -> {left, {stop, X}} end,
    fun(X) -> {right, X+100} end
]).

{ok, [1,2,3]} = erlz:error_do([
    fun() -> {ok, []} end,
    fun([] = State) -> {ok, State ++ [1]} end,
    fun([1] = State) -> {ok, State ++ [2]} end,
    fun([1,2] = State) -> {ok, State ++ [3]} end
]).

{error, "reason"} = erlz:error_do([
    fun() -> {ok, []} end,
    fun([] = State) -> {ok, State ++ [1]} end,
    fun([1] = State) -> {error, "reason"} end,
    fun([1,2] = State) -> {ok, State ++ [3]} end
]).

Traversable

Example of traverse on Erlang

Fn = fun(Item) ->
    case Item > 5 of
        true -> {left, "Contains value greater than 5"};
        _ -> {right, Item * 2}
    end
end,

{left,"Contains value greater than 5"} = erlz:either_traverse(Fn, [6,1,2,3,4]).

{right,[2,4,6,8]} = erlz:either_traverse(Fn, [1,2,3,4]).

A similar example as above but on Haskell

> (traverse 
    (\x -> if x > 5 then Left ("Contains value greater than 5") else Right (x * 2))
    [6, 1..5])
Left "Contains value greater than 5"


> (traverse 
    (\x -> if x > 5 then Left ("Contains value greater than 5") else Right (x * 2))
    [1..5])
Right [2,4,6,8,10]

foldM

Simple example

Fn = fun(X, Sum) ->
    case X > 5 of
        true -> {left, "Contains value greater than 5"};
        _ -> {right, Sum + X}
    end
end,
{right,3} = erlz:either_foldlM(Fn, 0, [1,1,1]),
{left,"Contains value greater than 5"} = erlz:either_foldlM(Fn, 0, [6,1,1]).

and analogue on Haskell

> let f = (\acc x -> if x > 5 then Left ("Contains value greater than 5") else Right (acc + x)) in foldlM f 0 [1,1,1]
Right 3
> let f = (\acc x -> if x > 5 then Left ("Contains value greater than 5") else Right (acc + x)) in foldlM f 0 [6,1,1]
Left "Contains value greater than 5"