Last active
December 18, 2015 05:39
-
-
Save ericmoritz/5734333 to your computer and use it in GitHub Desktop.
I think I finally understand monads!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(erlmonad). | |
-compile(export_all). | |
half(X) when X rem 2 =/= 0 -> | |
nothing; | |
half(X) -> | |
X div 2. | |
divide(_X, 0) -> | |
{error, divbyzero}; | |
divide(X, Y) -> | |
{ok, X / Y}. | |
error_m(E={error, _}, State) -> | |
fun(bind,_) -> | |
error_m(E, State); | |
(return,_) -> | |
{E, State} | |
end; | |
error_m({ok, V}, State) -> | |
fun(bind, F) -> | |
F(V, State); | |
(return,_) -> | |
{{ok, V}, State} | |
end; | |
error_m(V, State) -> | |
fun(bind, F) -> | |
F(V, State); | |
(return,_) -> | |
{V, State} | |
end. | |
maybe(nothing, State) -> | |
fun(bind,_) -> | |
maybe(nothing, State); | |
(return,_) -> | |
nothing | |
end; | |
maybe(V, State) -> | |
fun(bind, F) -> | |
F(V, State); | |
(return,_) -> | |
{V, State} | |
end. | |
identity(X) -> X. | |
do([InitialOp|Rest]) -> | |
fun(V, State) -> | |
R = lists:foldl( | |
fun(Op, M) -> | |
M(bind, Op) | |
end, | |
InitialOp(V, State), | |
Rest | |
), | |
R(return, '_') | |
end. | |
input_example() -> | |
AssertInt = fun(N, State) when is_integer(N) -> error_m(N, State); | |
(_, State) -> error_m({error, not_int}, State) end, | |
F = do([ | |
% Ask for an integer | |
fun(_, State) -> | |
Read = io:read("Int> "), | |
error_m(Read, State) end, | |
% assert that we read an int | |
AssertInt, | |
% Ask for another integer | |
fun(N1, _) -> | |
Read = io:read("Int> "), | |
% keep the first int we read as the state | |
error_m(Read, N1) end, | |
% assert the 2nd term we read is an int, | |
AssertInt, | |
% Add the two integers together | |
fun(N2, N1) -> maybe(N2 + N1, '_') end | |
]), | |
% execute the operations | |
F('_', init). | |
error_example(N) -> | |
F = do([ | |
fun(X, State) -> error_m(divide(10, X), State) end, | |
fun(X, State) -> error_m(divide(X, 5), State) end, | |
fun(X, State) -> maybe(X, State) end | |
]), | |
F(N, nostate). | |
half_example(N) -> | |
F = do([ | |
fun(X, State) -> maybe(half(X), State) end, | |
fun(X, State) -> maybe(half(X), State) end, | |
fun(X, State) -> maybe(half(X), State) end | |
]), | |
F(N, nostate). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment