Skip to content

Instantly share code, notes, and snippets.

@taiki45
Last active December 29, 2015 01:39
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save taiki45/7594394 to your computer and use it in GitHub Desktop.
Save taiki45/7594394 to your computer and use it in GitHub Desktop.
How monads work for OOProgrammers. Monad in object-oriented-language is useless unless for leaning.
import Control.Monad
bind :: (Monad m, Functor m) => m a -> (a -> m b) -> m b
bind m f = join (fmap f m)
unit :: Monad m => a -> m a
unit = return
compose :: (b -> c) -> (a -> b) -> (a -> c)
compose = (.)
plus1 :: Num a => a -> a
plus1 x = x + 1
multiple5 :: Num a => a -> a
multiple5 x = x * 5
plus1OrNothing :: (Num a, Ord a) => a -> Maybe a
plus1OrNothing x = if x > 10 then Just (x + 1) else Nothing
multiple5OrNothing :: (Num a, Ord a) => a -> Maybe a
multiple5OrNothing x = if x > 20 then Just (x * 5) else Nothing
-- Num a => Maybe a >>= (a -> Maybe a) >>= (a -> Maybe a)
-- Maybe Int >>= (Int -> Maybe Int) >>= (Int -> Maybe Int)
bindResult1 = Just 4 >>= plus1OrNothing >>= multiple5OrNothing -- Nothing
bindResult2 = Just 30 >>= plus1OrNothing >>= multiple5OrNothing -- Just 155
bindResult3 = Nothing >>= plus1OrNothing >>= multiple5OrNothing -- Nothing
{-- Read line from STDIN, then convert it to proper type and add 5, then
output it to STDOUT:
getLine >>= (\a -> print $ (read a) + 5)
getLine :: IO String
read :: Read a => String -> a
print :: Show a => a -> IO ()
So we do `(IO String) >>= (String -> IO ())`.
bind is useful
--}
// : Number -> Number
function plus1(x) { return x + 1; }
// : Number -> Number
function multiple5(x) { return x * 5; }
// example, not used
// : Maybe a
var Maybe = {
value: null, // a
nothing: true // bool
};
// : a -> Maybe a
function Just(a) {
return {
value: a,
nothing: false
};
}
// : Maybe a
function Nothing() {
return {
value: undefined,
nothing: true
};
}
//==== Story1
// Monads are Functor.
// : (a -> b) -> Maybe a -> Maybe b
function fmap(f, m) {
if(m.nothing) {
return Nothing();
} else {
return Just(f(m.value));
}
}
fmap(plus1, Just(4)) //=> Just 5
fmap(plus1, Nothing()) //=> Nothing
//==== Story2
// Monad's bind operator.
// bind is equivalent to >>=.
// : Maybe a -> (a -> Maybe b) -> Maybe b
function bind(m, f) {
if(m.nothing) {
return Nothing();
} else {
return f(m.value);
}
}
function plus1OrNothing(x) {
if(x > 10) {
return Just(x + 1);
} else {
return Nothing();
}
}
function multiple5OrNothing(x) {
if(x > 20) {
return Just(x * 5);
} else {
return Nothing();
}
}
bind(bind(Just(4), plus1OrNothing), multiple5OrNothing) //=> Nothing
bind(bind(Just(30), plus1OrNothing), multiple5OrNothing) //=> Just 155
bind(bind(Nothing(), plus1OrNothing), multiple5OrNothing) //=> Nothing
//==== Story3
// join is equivalent to return and bind.
// bind is equivalent to join and fmap.
// unit is equivalent to return.
// : a -> Maybe a
function unit(a) {
return Just(a);
}
// : Maybe (Maybe a) -> Maybe a
function join(m) {
if(m.nothing || m.value.nothing) {
return Nothing();
} else {
return Just(m.value.value); // == m.value
}
}
// : (b -> W) -> (a -> b) -> (a -> W)
function compose(g, f) {
return function(a) { return g(f(a)); };
}
// : a -> a
function id(a) {
return a;
}
// : Maybe Maybe a -> (a -> Maybe b) -> Maybe b
function bind2(m, f) {
return join(fmap(f, m));
}
// : Maybe Maybe a -> (a -> Maybe b) -> Maybe b
function join2(m) {
return bind(m, id)
}
def plus1(x):
return x + 1
def multiple5(x):
return x * 5
class Maybe(object):
def __init__(self, value, nothing=None):
self.value = value
self.nothing = nothing
def __repr__(self):
if self.nothing:
return "Nothing"
else:
return "Just %s" % self.value
# : a -> Maybe a
def Just(a):
return Maybe(a)
# : Maybe a
def Nothing():
return Maybe(None, True)
#==== Story1
# Monads are Functor.
# : (a -> b) -> Maybe a -> Maybe b
def fmap(f, m):
if m.nothing:
return Nothing()
else:
return Just(f(m.value))
fmap(plus1, Just(4)) #=> Just 5
fmap(plus1, Nothing()) #=> Nothing
#==== Story2
# Monad's bind operator.
# bind is equivalent to >>=.
# : Maybe a -> (a -> Maybe b) -> Maybe b
def bind(m, f):
if m.nothing:
return Nothing()
else:
return f(m.value)
def plus1OrNothing(x):
if x > 10:
return Just(x + 1)
else:
return Nothing()
def multiple5OrNothing(x):
if x > 20:
return Just(x * 5)
else:
return Nothing()
bind(bind(Just(4), plus1OrNothing), multiple5OrNothing) #=> Nothing
bind(bind(Just(30), plus1OrNothing), multiple5OrNothing) #=> Just 155
bind(bind(Nothing(), plus1OrNothing), multiple5OrNothing) #=> Nothing
#==== Story3
# join is equivalent to return and bind.
# bind is equivalent to join and fmap.
# unit is equivalent to return.
# : a -> Maybe a
def unit(a):
return Just(a)
# : Maybe (Maybe a) -> Maybe a
def join(m):
if m.nothing or m.value.nothing:
return Nothing()
else:
return Just(m.value.value) # == m.value
# : (b -> c) -> (a -> b) -> (a -> c)
def compose(g, f):
return (lambda a: g(f(a)) )
# : a -> a
def id(a):
return a
# : Maybe Maybe a -> (a -> Maybe b) -> Maybe b
def bind2(m, f):
return join(fmap(f, m))
# : Maybe Maybe a -> (a -> Maybe b) -> Maybe b
def join2(m):
return bind(m, id)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment