Lecture 16.0 — 2017-03-23
Monads
This lecture is written in literate Haskell; you can download the raw source.
import Data.Char
import Control.Applicative
import Data.IORef
newtype Parser a = Parser { parse :: String -> Maybe (a,String) }
instance Functor Parser where
fmap f p = Parser $ \s ->
case parse p s of
Nothing -> Nothing
Just (v,s') -> Just (f v,s')
instance Applicative Parser where
pure a = Parser $ \s -> Just (a,s)
f <*> a = Parser $ \s ->
case parse f s of
Nothing -> Nothing
Just (g,s') -> parse (fmap g a) s'
eof :: Parser ()
eof = Parser $ \s -> if null s then Just ((),"") else Nothing
ensure :: (a -> Bool) -> Parser a -> Parser a
ensure pred p = Parser $ \s ->
case parse p s of
Nothing -> Nothing
Just (a,s') -> if pred a then Just (a,s') else Nothing
satisfy :: (Char -> Bool) -> Parser Char
satisfy p = Parser f
where f [] = Nothing
f (x:xs) = if p x then Just (x,xs) else Nothing
lookahead :: Parser (Maybe Char)
lookahead = Parser f
where f [] = Just (Nothing,[])
f (c:s) = Just (Just c,c:s)
instance Alternative Parser where
empty = Parser $ \s -> Nothing
p1 <|> p2 = Parser $ \s ->
case parse p1 s of
Just (a,s') -> Just (a,s')
Nothing -> parse p2 s
int :: Parser Int
int = read <$> some (satisfy isDigit)
spaces :: Parser ()
spaces = many (satisfy isSpace) *> pure ()
char :: Char -> Parser Char
char c = spaces *> satisfy (==c)
plus, minus, times :: Parser Char
plus = char '+'
minus = char '-'
times = char '*'
num :: Parser Int
num = spaces *> int
data Arith =
Num Int
| Plus Arith Arith
| Times Arith Arith
| Neg Arith
deriving Show
sub :: Arith -> Arith -> Arith
sub a b = Plus a (Neg b)
addop,mulop :: Parser (Arith -> Arith -> Arith)
addop = plus *> pure Plus
<|> minus *> pure sub
mulop = times *> pure Times
term, factor, neg, atom :: Parser Arith
term = factor `chainl1` addop
factor = neg `chainl1` mulop
neg = Neg <$> (minus *> atom)
<|> atom
atom = Num <$> num
<|> (char '(' *> (term <* char ')'))
chainl1 :: Parser a -> Parser (a -> a -> a) -> Parser a
chainl1 p sep = foldl (\acc (oper,v) -> oper acc v)
<$> p <*> many ((\op v -> (op,v)) <$> sep <*> p)
sepBy1 :: Parser a -> Parser b -> Parser [a]
sepBy1 p sep = (:) <$> p <*> many (sep *> p)
sequenceA' :: Applicative f => [f a] -> f [a]
sequenceA' [] = pure []
sequenceA' (p:ps) = (:) <$> p <*> sequenceA' ps
sequenceA'' :: Applicative f => [f a] -> f [a]
sequenceA'' = foldr (liftA2 (:)) (pure [])
instance Monad Parser where
p >>= k = Parser $ \s ->
case parse p s of
Nothing -> Nothing
Just (v,s') -> parse (k v) s'
ott = [1..5] >>= (\n1 ->
[1..n1] >>= (\n2 ->
return (n1 + n2)))
refs = newIORef True >>= \ref ->
writeIORef ref False >>
readIORef ref
But, dangerously, you’ll get the following in GHCi:
let a = newIORef True
a >>= \ref -> writeIORef ref False
a >>= redIORef -- yields True!
a >>= \ref -> writeIORef ref False >> readIORef ref -- yields False
main = putStr "What's your name? " >> hFlush stdout >> getLine >>= \s -> putStrLn ("Hello, " ++ s ++ "!")