(a) Consider a simple parser library with the following type signature. Explain what this type represents and how it works.

newtype Parser a = Parser { runParser :: String -> Maybe (a, String) }

(c) Consider the following JSON-like syntax:

data JValue = JString String
            | JNumber Double
            | JBool Bool
            | JNull
            | JArray [JValue]
            | JObject [(String, JValue)]

Implement a parser for the JArray constructor, which parses arrays of the form [value1, value2, ...].

(e) Implement a parser combinator chainl1 that parses left-associative expressions with a given operator.

chainl1 :: Parser a -> Parser (a -> a -> a) -> Parser a

Then use it to implement a simple calculator supporting addition, subtraction, multiplication, and division with the correct operator precedence.

Monad Transformers

(c) Implement the following functions for the StateT monad transformer:

get :: Monad m => StateT s m s
put :: Monad m => s -> StateT s m ()
modify :: Monad m => (s -> s) -> StateT s m ()

Equational Reasoning

(a) Consider the following Haskell function:

map f (filter p xs) = filter p (map f xs)

Is this equation always true? Prove your answer using equational reasoning.

(b) Using equational reasoning, prove that foldr f z (xs ++ ys) = foldr f (foldr f z ys) xs for any function f, value z, and lists xs and ys.

Lambda Calculus (Extended Examples)

(a) Convert the following lambda expressions to their equivalent Haskell functions:

  1. λx.λy. x y x
  2. λf.λg.λx. f (g x)
  3. λf.λg.λx. f x (g x)

(b) Encode the following concepts in the untyped lambda calculus:

  1. Boolean values TRUE and FALSE, and the IF-THEN-ELSE construct
  2. Implement the logical AND operation using these encodings