Skip to content

Instantly share code, notes, and snippets.

@jwthomp
Created January 25, 2012 04:46
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jwthomp/1674783 to your computer and use it in GitHub Desktop.
Save jwthomp/1674783 to your computer and use it in GitHub Desktop.
Erlang Monad
-module(monad).
-export([ monad_context/2, putst/1, getst/0, lift/0, return/1 ]).
-export([ test/0 ]).
%%%%%%%%%%%%%%%%%%%%% Erlang Monad %%%%%%%%%%%%%%%%%%%%%%
%% Working on a simple monad implementation for Erlang %%
%% %%
%% Just for fun I tried whipping up a simple erlang %%
%% monad. It uses the process dictionary and I haven't %%
%% implemented lift and many children of a monad state %%
%% yet. Otherwise it works (with minor testing). %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
test() -> test(0).
test(State) ->
_Fun1 = fun(_X) ->
S = getst(),
S + 2
end,
_Fun2 = fun(X) ->
S = getst(),
putst(X * 2),
return(S)
end,
monad_context([fun add2ToState/1, fun mul2/1, fun store_ret/1 ], State).
add2ToState(_X) -> S = getst(), S + 2.
mul2(X) -> X * 2.
store_ret(X) -> putst(X), return(X).
monad_context(FunList, InitialState) ->
push_monad(InitialState),
do_runner(nil, FunList).
%% Put state
putst(State) -> put_state(State).
%% Get state
getst() -> get_state().
%%%%%% TODO %%%%%%
%% Lift up a state
lift() -> ok.
return(X) -> {return, {X, pop_monad()}}.
%% Internal %%
push_monad(InitialState) ->
case get(monad_state) of
undefined -> State = [];
State -> ok
end,
put(monad_state, [InitialState | State]),
[InitialState | State].
pop_monad() ->
[State | Rest] = get(monad_state),
put(monad_state, Rest),
State.
get_state() ->
[State | _Rest] = get(monad_state),
State.
put_state(State) ->
[_StateOld | Rest] = get(monad_state),
put(monad_state, [State | Rest]).
do_runner({return, {X, State}}, _) -> {ok, {X, State}};
do_runner(_X, []) -> {error, no_return};
do_runner(X, [Fun | RestFuns]) ->
X2 = Fun(X),
do_runner(X2, RestFuns).
-module(monad2).
%-export([ bind/2, return/1, get/0, put/1, runstate/2 ]).
-export([ bind/2, bind_/2, return/1, run/1, raise/1 ]).
% error monad {status, value}
% status = error | ok
% M = {state, Value}
% F(M) -> M'
% M() -> Mdata
% runstate(bind(get(), fun(X) -> put(X+1) end), 1)
%%FMAP
%% Take a function T (and Transformer) and wrap it into our monad
%% so that we can transform results
% T => function like tolower(X)
% M => X
% fmap(T,M) -> M'
fmap(T, M) ->
bind(M, fun(X) -> return(T(X)) end).
%% EXCEPTION HANDLER
bind(M,F) ->
fun() ->
case M() of
{ok, X} -> (F(X))();
{error, Reason} -> {error, Reason}
end
end.
bind_(M1, M2) -> bind(M1, fun(_) -> M2 end).
raise(X) -> fun() -> {error, X} end.
return(X) -> fun() -> {ok, X} end.
run(M) -> M().
%% STATE
%% bind from one parse combinator to the next
%bind (M,F) ->
% fun (ST) ->
% case M(ST) of
% {X,NewState} -> (F(X))({ok,NewState});
% Error -> Error
% end
% end.
%return(X) ->
% fun ({_, State}) -> {X, State} ;
% (Error) -> Error
% end.
% State monad
%get() ->
% fun({_, State}) -> {State, State} end.
%put(NewState) ->
% fun({_,_}) -> {ok, NewState} end.
%runstate(M, State) ->
% M({undefined, State}).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment