Lecture 19 — 2015-11-11
Parsing with Applicative
This lecture is written in literate Haskell; you can download the raw source.
module Lec19 where
import Control.Applicative
import Control.Monad
import Data.Char
import qualified Data.Map as Map
import Data.Map (Map, (!))
import Lec18 hiding (name, map)First, we remembered the definitions of Functor and Applicative from last time.
name :: Maybe String -> Maybe String -> Maybe String
name given family = (++) <$> given <*> family
drdave = name (Just "Dave") (Just "Kauchak")
prince = name (Just "Prince") Nothingdata CouldBe a = Nope | Yep a
instance Functor CouldBe where
  fmap f Nope = Nope
  fmap f (Yep a) = Yep $ f a
  
instance Applicative CouldBe where
  pure x = Yep x
  
  Nope <*> _ = Nope
  _ <*> Nope = Nope
  (Yep f) <*> (Yep x) = Yep $ f xThen we went over the Applicative definitions for lists.
instance Applicative [] where
  pure x = [x]
  []     <*>  _ = []
  _      <*> [] = []
  (f:fs) <*> xs = map f xs ++ fs <*> xs
note REPEAT call… why?
newtype ZipList a = ZipList { getZipList :: [a] }
  deriving (Eq, Show, Functor)
instance Applicative ZipList where
  pure = ZipList . repeat
  ZipList fs <*> ZipList xs = ZipList (zipWith ($) fs xs)
sequenceA :: (Applicative f) => [f a] -> f [a]  
sequenceA [] = pure []  
sequenceA (x:xs) = (:) <$> x <*> sequenceA xs
instance Applicative ((->) r) where
  pure x = const x
           
  f <*> g = \x -> f x (g x)
eg1 = (+) <$> (+3) <*> (*100)
eg2 = map (\f -> f 7) [(>4),(<10),odd]
eg3 = and $ sequenceA [(>4),(<10),odd] 7  
Readers
A Reader is a type that reads from some environmental source of input.
newtype Reader r a = Reader { runReader :: r -> a }
instance Functor (Reader r) where
  fmap f (Reader g) = Reader $ f . g
instance Applicative (Reader r) where
  pure = Reader . const
  (Reader f) <*> (Reader g) = Reader $ \x -> f x (g x)
get :: Reader r r
get = Reader $ \x -> x
data Exp x = Var x | Val Int | Add (Exp x) (Exp x)
type Env x = Map x Int
evalExp :: Ord x => Exp x -> Env x -> Int
evalExp (Var x) env = env ! x
evalExp (Val i) env = i
evalExp (Add e1 e2) env = (evalExp e1 env) + (evalExp e2 env)
evalExp' :: Ord x => Exp x -> Reader (Env x) Int
evalExp' (Var x) = (!x) <$> get
evalExp' (Val i) = pure i
evalExp' (Add e1 e2) = (+) <$> evalExp' e1 <*> evalExp' e2
Parsers using Applicative
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'
instance Alternative Parser where
  empty = Parser $ const empty
  l <|> r = Parser $ \s -> parse l s <|> parse r s
char :: Char -> Parser Char
char c = spaces *> satisfy (==c)
str :: String -> Parser String
str s = spaces *> (sequenceA $ map (satisfy . (==)) s)
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
lookahead :: Parser (Maybe Char)
lookahead = Parser f
  where f [] = Just (Nothing,[])
        f (c:s) = Just (Just c,c:s)
eof :: Parser ()
eof = Parser $ \s -> if null s then Just ((),[]) else Nothing
zeroOrMore, oneOrMore :: Parser a -> Parser [a]
oneOrMore p = (:) <$> p <*> zeroOrMore p -- a/k/a some
zeroOrMore p = oneOrMore p <|> pure [] -- a/k/a many
opt :: Alternative f => f a -> f (Maybe a)
opt f = (Just <$> f) <|> (pure 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
data Arith = Num Int | Plus Arith Arith | Times Arith Arith deriving Show
spaces :: Parser ()
spaces = pure () <* zeroOrMore (satisfy isSpace)
term :: Parser Arith
term = ((Plus <$> (factor <* char '+')) <*> term) <|> factor
factor :: Parser Arith
factor = Times <$> atom <* char '*' <*> factor <|> atom
atom :: Parser Arith
atom = num <|> (char '(' *> term <* char ')')
num :: Parser Arith
num = spaces *> (Num . read <$> oneOrMore (satisfy isDigit))