Sei sulla pagina 1di 18

Short overview of monads

(or, a few different views of monads)


So, what is a monad?
Monads are just burritos

http://chrisdone.com/posts/monads-are-burritos
Monad is an interface

Fits well into modeling some problems


passing some additional context around: IO, (mutable) state,
exceptions, concurrency (async code and futures)

Components
datatype and encapsulation
composable functions
monad laws

Actions
sequential (daisy) chaining
provides do notation
Can model imperative aspects of programming
Can combine pure and unpure code
Main part of the monad definition
Bind
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b

*Pictures taken from very nice pictorial explanations of monads given in this blog post
Maybe/Option
Maybe type
as a monad

wrap a computation inside it


half x = if even x
then Just (x `div` 2)
else Nothing

cannot be applied directly


half $ Just 3
Maybe monad, bind
We need bind
instance Monad Maybe where
Nothing >>= func = Nothing
Just val >>= func = func val

Handles both cases


of Maybe
Maybe, chaining
Successive applications of our computation

> Just 20 >>= half >>= half >>= half


Nothing
Handling unpure code
Haskell is a purely functional language
Mechanism for handling unpure code
side effects
state and mutations
Solution? Encapsulate unpure things
into a monad
use bind to effectively combine it with pure code
Once you have unpure code, you cannot escape
contrast with, e.g. Maybe monad
the concept of escaping a monad
IO monad
Like others, but also special
Provided operations
getLine :: IO String
readFile :: FilePath -> IO String
putStrLn :: String -> IO ()
unit type
getLine >>= readFile >>= putStrLn (eff. no value)

foo = do
filename <- getLine
contents <- readFile filename
putStrLn contents
Benefits of the interface
data Expr = Val Int | Div Expr Expr > eval (Div (Val 4) (Val 2))
2

we want to write
this evaluator
Benefits of the interface
data Expr = Val Int | Div Expr Expr > eval (Div (Val 1) (Val 0))
*** Exception: divide by zero
eval :: Expr -> Int
eval (Val n) = n
eval (Div x y) = eval x div eval y we want to
avoid this error

simple
implementation
Benefits of the interface
data Expr = Val Int | Div Expr Expr > eval (Div (Val 1) (Val 0))
*** Exception: divide by zero
eval :: Expr -> Int
eval (Val n) = n safediv :: Int -> Int -> Maybe Int
eval (Div x y) = eval x div eval y safediv _ 0 = Nothing
safediv n m = Just (n div m)

eval :: Expr -> Maybe Int


eval (Val n) = Just n Our evaluator with a safe
eval (Div x y) = case eval x of division, as a monad
Nothing -> Nothing
Just n -> case eval y of
Nothing -> Nothing
Just m -> safediv n m

> eval (Div (Val 1) (Val 0))


Nothing
Benefits of the interface
data Expr = Val Int | Div Expr Expr > eval (Div (Val 1) (Val 0))
*** Exception: divide by zero
eval :: Expr -> Int
eval (Val n) = n safediv :: Int -> Int -> Maybe Int
eval (Div x y) = eval x div eval y safediv _ 0 = Nothing
safediv n m = Just (n div m)

eval :: Expr -> Maybe Int


eval (Val n) = Just n
eval (Div x y) = case eval x of
Nothing -> Nothing eval :: Expr -> Maybe Int
Just n -> case eval y of eval (Val n) = Just n
Nothing -> Nothing eval (Div x y) =
Just m -> safediv n m do n <- eval x
m <- eval y
> eval (Div (Val 1) (Val 0)) safediv n m
Nothing do notation makes it
a bit more concise
Rest of the interface
Full Interface (>>=) :: forall a b. m a -> (a -> m b) -> m b
(>>) :: forall a b. m a -> m b -> m b
return :: a -> m a
fail :: String -> m a

Pattern matching
might fail
do { action1 x1
; mk_action3 x1 x2 }
do { True <- action1 x1
; x2 <- action2 do { putString(Hello)
; action3 x1 x2 } putString(World)
return () }

Fail is called
action1 x1 >>= f >>
where similar to bind
f True = do { x2 <- action2; mk_action3 x1 x2 } but does not use value
f_ = fail "..." -- A compiler-generated message.
Monad laws
Left identity: return a >>= k =ka
Right identity:
m >>= return =m
which gives us

do { x <- return x; f x } do { f x }

identity law says two are equivalent


Associativity
gives us m >>= (\x -> k x >>= h) = (m >>= k) >>= h
do do
y <- do
x <- m x <- m
equivalent due to
y <- k x <=> k x
h y h y associativity law

Note that developers need to ensure laws hold


Monad types
Writer monad
(similar to the one given in lectures)

Reader monad

State monad
Writer monad
Example of using writer monad
data Writer w a = Writer { runWriter :: (a, w) }

half :: Int -> Writer String Int


half x = do
tell ("I just halved " ++ (show x) ++ "!")
return (x `div` 2)

runWriter $ half 8 >>= half


=> (2, "I just halved 8!I just halved 4!")

Potrebbero piacerti anche