# Monadic Parsing --- CS 135 // 2021-03-18 ## Administrivia - Lab 6 deadline pushed back one week - Check in - Midterm presentations start next week + Here is the [rubric](/teaching/2021s/cs135/assets/rubric.txt) I will use # Questions ## ...about anything? # Lab 5b Debrief # Review ## Functor Typeclass - The `Functor` typeclass exactly captures this idea of map and is defined as ```haskell class Functor f where fmap :: (a -> b) -> f a -> f b ``` - Note that `f` must be a **parameterized** type such as `Maybe` or `Tree` or a list ## Applicative Typeclass - The `Applicative` typeclass captures the idea of mapping functions with arbitrarily many parameters over data structures ```haskell class Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b ``` - For example: ```text Prelude> pure (+) <*> (Just 3) <*> (Just 5) Just 5 ``` ## Monad Typeclass - The `Monad` typeclass even further generalizes structural composition and looks like this: ```haskell class Monad m where return :: a -> m a (>>=) :: m a -> (a -> m b) -> m b ``` ## Monad Instance for Maybe - We created an instance for `Maybe` with: ```haskell instance Monad Maybe where -- return :: a -> Maybe a return = Just -- (>>=) :: Maybe a -> (a -> Maybe b) -- -> Maybe b Nothing >>= _ = Nothing (Just x) >>= f = f x ``` ## Application of Maybe Monad - Now suppose we have three operations: ```haskell f1 :: a -> Maybe b f2 :: b -> Maybe c f3 :: c -> Maybe d ``` - How could we compose them into a function? ```haskell f4 :: a -> Maybe d ``` ## Without a Monad - If `Maybe` wasn't a monad, our only choice is: ```haskell f4 x = case f1 x of Nothing -> Nothing Just y -> case f2 y of Nothing -> Nothing Just z -> f3 z ``` ## With a Monad - However, since `Maybe` is a monad, we can compose these operations in the following way: ```haskell f4 x = f1 x >>= \y -> f2 y >>= \z -> f3 z ``` - Composing monadic operations like this is so common, Haskell has special syntax for it: ```haskell f4 x = do y <- f1 x -- binds the result to y z <- f2 y -- binds the result to z f3 z -- the result of f3 is returned ``` # IO Monad ## Introducing the IO Monad - Haskell has a special monad, `IO`, for performing actions that have **side effects** - For example, consider the following `IO` values: ```haskell -- Gets one line from stdin getLine :: IO String -- Prints a string to stdout putStrLn :: String -> IO () ``` - `getLine` is similar to Python's `input()` function - `putStrLn` is similar to Python's `print()` function ## Using the IO Monad - Here is a Haskell program using the `IO` monad: ```haskell main :: IO () main = do putStr "Enter your first name: " name <- getLine putStrLn ("Hello, " ++ name ++ "!" ``` - Notice that `main` is not a function---it is a compound `IO` action - When the `IO` action is executed, it will execute these in sequence just as you'd expect ## Running a Haskell Program - If you have a Haskell program `Program.hs ` with a `main` function that is an `IO` action, you can run it from the command line with: ```text runhaskell Program.hs ``` ## Other IO Functions ```haskell -- Prints a showable value to stdout print :: Show a => a -> IO () -- Reads the entire contents of a file readFile :: FilePath -> IO String -- Writes the entire contents of a string to a file writeFile :: FilePath -> String -> IO () ``` # Parsing ## Introduction to Parsing - A **parser** is a program that takes a string as input and produces a **parse tree** as output - For example, the string `(3 + 4) * 2` might be parsed into the following tree:
tree
*
*
+
+
*->+
2
2
*->2
3
3
+->3
4
4
+->4
## Grammar for Expressions - Syntactic structure for arithmetic expressions can be formalized with a **grammar**: ```text expr ::= expr + expr | expr * expr | ( expr ) | natural natural ::= 0 | 1 | 2 | ... ``` - This grammar defines the "rules" for how an expression can be structured ## `(3+4)*2` Parse Tree
tree
e1
expr
e2
expr
e1->e2
*
*
e1->*
e3
expr
e1->e3
(
(
e2->(
e4
expr
e2->e4
)
)
e2->)
n1
nat
e3->n1
e5
expr
e4->e5
+
+
e4->+
e6
expr
e4->e6
n2
nat
e5->n2
n3
nat
e6->n3
2
2
n1->2
3
3
n2->3
4
4
n3->4
## Semantics of a Parse Tree - Parse trees can help us understand the meaning of an expression or statement + For example, the parse tree for `(3+4)*2` made it clear that `*` happens after the `+` - When compiling or running a program, we usually first *parse* the code into a tree and then *interpret* (i.e. evaluate) it afterwards + For example, evaluating `(3+4)*2` into `14` ## Ambiguous Grammars - Let's take a closer look at our grammar defined previously: ```text expr ::= expr + expr | expr * expr | ( expr ) | natural natural ::= 0 | 1 | 2 | ... ``` - How will the expression `3+4*2`? + It has two possible parsings! - This means the grammar is *ambiguous* ## Unambiguous Grammar - Now consider the following grammar: ```text expr ::= term + expr | term term ::= factor * term | factor factor ::= ( expr ) | natural natural ::= 0 | 1 | 2 | ... ``` - The rules force `+` to be evaluated after `*` # Monadic Parsing