Thursday, March 25, 2010

A Pattern to Reduce Erlang Complexity

Presented here is a recipe for reducing the complexity of a common programming pattern that is likely to appear in Erlang source code.  The solution pattern presented here is similar to the functional programming idiom known as "The Error Monad" whereby a series of function calls may or may not return an error.

Example Problem

withdraw_money(AccountNumber, Password, Amount) ->
  case account:find(AccountNumber) of
{ok, Account} ->
     case security:check_password(Password, Account) of
ok ->
        case dispenser:available_cash() < Amount of
true ->
           case account:withdraw(Amount) of
ok ->
              case dispenser:spit_out_cash(Amount) of
ok ->
                 ok;
DispenserError ->
                 DispenserError
              end;
WithdrawalError ->
              WithdrawalError
           end;
false ->
           {error, atm_is_empty}
        end;
SecurityError ->
        SecurityError
     end;
AccountError ->
     AccountError
  end.

Example Solution


-include("idiom-try-check-catch.hrl").


withdraw_money(AccountNumber, Password, Amount) ->
  try
{ok, Account} = check(account, find, AccountNumber),
check(security, check_password, Password, Account),
case check(dispenser, available_cash) < Amount of
     true ->
check(account, withdraw, Amount),
check(dispenser, spit_out_cash, Amount);
     false ->
{error, atm_is_empty}
end
  catch
throw:Reason ->
     {error, Reason}
  end.



Guts




-type reason() :: any().
-type error() :: {error, reason()}.
-type might_return_an_error() :: error() | any().

-spec f(Arg1, Arg2) -> error().


No comments:

Post a Comment