Last active
December 29, 2015 01:39
-
-
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.
This file contains hidden or 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
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 | |
--} |
This file contains hidden or 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
// : 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) | |
} |
This file contains hidden or 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
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