@jyrimatti
In addition to it begin useful, it is also cursed and the curse of the monad is that once you get the epiphany, once you understand - "oh that's what it is" - you lose the ability to explain it to anybody.
-- Douglas Crockford
it's not a burrito
http://www.carlosandgabbys.com/chicken%20burrito.jpgIn mathematics, a function is a relation between a set of inputs and a set of permissible outputs with the property that each input is related to exactly one output.
http://en.wikipedia.org/wiki/Function_(mathematics)
f :: a -> b
familiar with Haskell syntax?
In mathematics, function composition is the pointwise application of one function to the result of another to produce a third function.
http://en.wikipedia.org/wiki/Function_composition
compose :: (b -> c) -> (a -> b) -> (a -> c)
compose g f = \a -> g (f a)
= g . f
in mathematics, function application is the act of applying a function to an argument from its domain so as to obtain the corresponding value from its range.
http://en.wikipedia.org/wiki/Function_application
apply :: (a -> b) -> a -> b
what if our values are "boxed", inside:
noWay :: Bool -> Bool
someValue :: Maybe Bool
noWay someValue -- whoops, won't compile
In mathematics, a functor is a type of mapping between categories, which is applied in category theory.
http://en.wikipedia.org/wiki/Functor
just forget that.
class Functor f where
fmap :: (a -> b) -> f a -> f b
noWay :: Bool -> Bool
someValue :: Maybe Bool
(fmap noWay) someValue -- hooray!
what if our function takes more parameters?
orElse :: Bool -> Bool -> Bool
(fmap orElse) :: Maybe Bool -> Maybe (Bool -> Bool) -- whoops...
return value wrapped inside the container,
need something capable of handling this
class Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
notice how the signature is just what we needed
orElse :: Bool -> Bool -> Bool
someValue :: Maybe Bool
(pure orElse) <*> someValue <*> someValue -- hooray!
what if we want to interact with the box?
that is, affect the execution based on computed values?
that is, determine execution based on context?
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
we have a wrapped value, and we add "actions" to it one by one
(return 1) >>= (\one -> return (one + 1)) >>= (\two -> return (two + 1)) -- and so on...
notice how this enforces the order of execution
we can change the order of arguments:
(>>=) :: m a -> (a -> m b) -> m b
(=<<) :: (a -> m b) -> m a -> m b
now the first part (the initial monadic value) can be given last:
(\one -> return (one + 1) >>= (\two -> return (two + 1))) =<< (return 1)
simplify syntax:
(a -> m b >>= (b -> m c)) =<< m a
compare to function composition,
whose arguments may as well be interchanged:
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(>>>) :: (a -> b) -> (b -> c) -> (a -> c)
(a -> b) >>> (b -> c) $ a
monad generalizes function composition
to work with functions returning boxed values
Lifting is a concept which allows you to transform a function into a corresponding function within another (usually more general) setting.
https://www.haskell.org/haskellwiki/Lifting
functor/applicative/monad can be thought of as
an alternative way to apply functions
apply :: (a -> b) -> a -> b
fmap :: (a -> b) -> f a -> f b
(<*>) :: f (a -> b) -> f a -> f b
(=<<) :: (a -> m b) -> m a -> m b
or a function can be thought to be lifted to another context
fmap :: (a -> b) -> (f a -> f b)
liftA2 :: (a -> b -> c) -> (f a -> f b -> f c) -- and liftA, liftA3, ...
liftM2 :: (a -> b -> c) -> (m a -> m b -> m c) -- and liftM, liftM3, ...
anyway, it's just syntax
all these concepts must satisfy certain laws to ensure they are well behaved
we will not go there now =)
Monads have nothing to do with IO
...but IO needs the order of execution, which happens to be just the concept that a monad can provide
See https://www.haskell.org/haskellwiki/IO_inside for more info
class Functor f where
fmap :: (a -> b) -> f a -> f b
class Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b -- or: =<< :: (a -> m b) -> m a -> m b
apply :: (a -> b) -> a -> b
fmap :: (a -> b) -> f a -> f b
(<*>) :: f (a -> b) -> f a -> f b
=<< :: (a -> m b) -> m a -> m b
anything missing?
?? :: (w a -> b) -> w a -> w b
there's still A LOT more to learn.
go learn!
thank you.