CS 410/510 - Homework #4
Create a single Haskell file that contains solutions to the following problems. Be sure it compiles without errors, and submit it via D2L by class time on May April 1st, 2014. Start with the file HW4Template.html which is a variant of the TrivialParser we saw in lecture on Tuesday, and the simplePrinter we saw in lecture on Thursday. It has all the boiler plate you will need.

Be sure you put your name and e-mail in a comment at the beginning of the file. Without this you will not get any feedback.

In this homework you will write a parser for a subset of haskell. In order to do this you will need to write indentation sensitive parsers. Which keep track of the column that some sytactic entities start in. This is done with the parsec "layout" combinator. An example is given below that parses a "let" statement (given parsers for declarations (declP) and expressions ("expP")).

letParser declP expP =
  do { pos <- getPosition   -- This gets the SourcePos
     ; keyworD "let"
     ; ds <- layout declP (keyworD "in")  -- "in" ends the layout if it is found
     ; exp <- expP
     ; return(ds,exp)}
When a parser "p" is "layed out" a "tab stop" is set at the next non-whitespace character. It the parses a sequence of "p" objects. Lines that begin after the "tab stop" are continuations of the "p" that started on earlier lines. Lines that begin at the "tab stop" are the beginning of the next "p". Lines that start before the "tab stop" end the layout rule. The second argument to "layout" (keyworD "in") is a parser the forces the layout to end regardless of the where the line begins. Some layout sensisitve language copnstructs (such as case, where, and do) do not have a terminating token, in which case the parser (return ()) will do.

One can turn off the laout rule by surrounding the sequence of "p" objects by "{" and "}" separating by ";". Thus the following pairs all parse the same.

case x of
  [] -> 0
  (Cons x xs) -> x + 4

case x of { [] -> 0; (Cons x xs) -> x + 4}


let x = 3
    y = 5
in x + y

let {x = 3; y = 5} in x+5


f x y = x+y+z
  where a = 5
        z = a - 3

f x y = x+y+z where { a= 5; z = a-3}
Luckily all this is handled by the layout parser combinator. In order to use the layout combinator one needs a modified version of the Parsec.Token module. He one we use is called "LayoutToken" and is included here. Just download this file, along with HW4Template.html. Rename "HW4Template.html" to "hw4.hs", and keep both files in the same directory.

The language we are interested in has the following abstract syntax. This is a subset of Haskell expressions.

type Var = (SourcePos,String)  -- Starts lowercase
type Con = (SourcePos,String)  -- Starts with Upper case
type Name = (SourcePos,String) -- Starts with either lower case or uppercase

data Lit
  = Int Int
  | Char Char
  | Unit
  | Float Float

data Pat
  = Plit Lit                  -- { 5 or 'c' }
  | Pvar Var                  -- { x }
  | Pprod [Pat]               -- { (p1,p2,p3) }
  | Paspat Var Pat            -- { x @ p }
  | Pwild                     -- { _ }
  | Pcon Con [Pat]            -- C x y (z,a)

data Exp
  = Var Name                   -- { x  or  Nil }
  | Lit Lit                   -- { 5 or 'c'  or  5.6 }
  | Prod [Exp]                -- { (e1,e2,e3) }
  | App Exp Exp               -- { f x }
  | Lam [Pat] Exp             -- { \ p1 p2 -> e }
  | Let [Dec] Exp             -- { let { x=e1;   y=e2 } in e3 }
  | Case Exp [Match Pat Exp Dec]    -- { case e of { m1; m2 }}
  | Do [Stmt Pat Exp Dec]           -- { do { p <- e1; e2 } }

-- Let, Case, Do, all use layout

type Match p e d = (SourcePos,p,Body e,[d]) -- case e of { p -> b where decs }

data Body e
  = Guarded [(e,e)]           -- f p { | e1 = e2 | e3 = e4 } where ds
  | Normal e                  -- f p = { e } where ds
                              -- Where uses layout

data Stmt p e d
  = BindSt SourcePos p e
  | LetSt SourcePos [d]
  | NoBindSt SourcePos e

data Dec
  = Fun SourcePos Var [Match [Pat] Exp Dec]   -- { f p1 p2 = b where decs }
  | Val SourcePos Pat (Body Exp) [Dec]        -- { p = b where decs }
Here is what I expect.
  1. Download the necessary files.
  2. Rename "HW4Template.html" to "hw4.hs".
  3. make additions to "hw4.hs" so that it does the following
    1. parses a sequence of Haskell declarations.
    2. pretty prints the list of declarations
    3. contains both a "main" function and a "test" function
  4. Write a Main function that tests your homework.
    1. Create a test file that has at least one example of every syntactic element.
    2. Parse from the test file to obtain [Dec]
    3. Pretty print the parsed data.
    4. write the pretty printed string to a file.
    5. show that this file can be parsed.
  5. Write a test function that
    1. Reads a string typed by the user.
    2. Parse the string as an Exp.
    3. Pretty prints the parsed string.
    4. reports useful errors when the parsing fails.
    5. and then repeats, getting another string fro the user.
  6. Zip everything up in a zip file and submit via D2L.