module HW3 where import List {- For each of the following questions, put your answer directly below the question. This homework is due on Friday, October 16, by 3pm. Email your code directly to Adam Procter: amp269@mizzou.edu. (1) You must use a text editor (e.g., vi, textpad, emacs, etc.) to prepare your solution. (2) You must write type declarations for each and every one of your Haskell definitions. (3) The program you turn in must be the product of your effort alone. -} {- Question 1. Write the BNF grammar corresponding to Lam. data Lam = Var String | App Lam Lam | Lambda String Lam ::= Var | App | Lambda Var I use brackets here to distinguish non-terminals from terminals (although you needn't have done so). Note that the only different between this BNF and the data declaration is how terminals are handled. To represent a terminal in the data declaration, one typically chooses a reasonable type. String is such a reasonable choice for Var. This String type is also used as the first argument of the Lambda constructor. Some might be tempted to try some nonsense like "... | Lambda (Var String) Lam", but they should resist this temptation. -} data Symbol = Nonterminal String | Terminal String data Production = String :--> [Symbol] {- Question 2. Write instance declarations for Symbol and Production for the Show class. To display a non-terminal, wrap it with brackets "<" and ">". -} instance Show Symbol where show (Nonterminal s) = "<" ++ s ++ ">" show (Terminal s) = s instance Show Production where show (nt :--> rhs) = nt ++ " --> " ++ space (map show rhs) where space = foldr sp "" sp x xs = case xs of "" -> x _ -> x ++ " " ++ xs {- Question 3. The following data type represents grammars as separate sets of terminals and nonterminals (both represented by [String]) and a set of productions (represented by [Production]). For example, consider the grammar we saw in class: Exp --> Int Exp --> Exp + Exp Exp --> Exp * Exp This would be represented as a grammar by arithgrammar below. Note that a value of type Grammar may *not* represent a grammar. Say badgrammar = Grammar nts ts ps, then badgrammar is bad: 1. If there is a production in ps, x :--> xs, where x is not in nts, or 2. There is a nonterminal occuring in xs that does not occur in nts, or 3. There is a terminal occuring in xs that does not occur in ts, or 4. nts and ts have some symbol in common. Write a function, goodgrammar :: Grammar -> Bool, that returns True if its argument is not bad, and false if it is bad. -} -- I said in class that you may use the List library. -- It isn't necessary, though, if you don't, you will in effect -- implement these same functions: contained x y = x == intersect x y -- checks 1. above one (Grammar nts ts ps) = contained lhss nts where lhss = map (\ (nt :--> _) -> nt) ps -- checks 2. above two (Grammar nts ts ps) = contained pnts nts where symbols = concat (map (\ (_ :--> rhs) -> rhs) ps) pnts = foldr getnts [] symbols getnts (Terminal _) rs = rs getnts (Nonterminal x) rs = x : rs -- checks 3. above three (Grammar nts ts ps) = contained pts ts where symbols = concat (map (\ (_ :--> rhs) -> rhs) ps) pts = foldr getts [] symbols getts (Terminal x) rs = x : rs getts (Nonterminal _) rs = rs -- checks 4. above four (Grammar nts ts ps) = null (intersect nts ts) goodgrammar g = one g && two g && three g && four g data Grammar = Grammar [String] -- non-terminals [String] -- terminals [Production] -- productions arithgrammar = Grammar nonterminals terminals productions where nonterminals = ["Exp"] terminals = ["Int","+","*"] productions = ["Exp" :--> [Terminal "Int"], "Exp" :--> [Nonterminal "Exp", Terminal "+", Nonterminal "Exp"], "Exp" :--> [Nonterminal "Exp", Terminal "*", Nonterminal "Exp"]] {- Question 4. We saw the following grammar in the LanguageProcessing1 slides: Exp ::= ( Op ExpList ) Exp ::= Int | Real Op ::= + | - | * | / ExpList ::= Exp ExpList ExpList ::= In this last production, I have left the lambda out. Represent this grammar as a Grammar value. -} question4 = Grammar nonterminals terminals productions where nonterminals = ["Exp","Op","ExpList"] terminals = ["Int","Real","+","-","*","/","(",")"] productions = ["Exp" :--> [Terminal "(", Nonterminal "Op", Nonterminal "ExpList", Terminal ")"], "Op" :--> [Terminal "+"], "Op" :--> [Terminal "-"], "Op" :--> [Terminal "*"], "Op" :--> [Terminal "/"], "Exp" :--> [Terminal "Int"], "Exp" :--> [Terminal "Real"], "ExpList" :--> [], "ExpList" :--> [Nonterminal "Exp", Nonterminal "ExpList"]] {- Question 5. The following is a derivation in the grammar from Question 4 (it also comes from the same slide set). Exp => ( Op ExpList ) => ( + ExpList ) => ( + Exp ExpList ) => ( + 1 ExpList ) => ( + 1 Exp ExpList ) => ( + 1 2 ExpList ) => ( + 1 2 ) A derivation can be represented by a list of lists, [s1,...,sn], where each si :: [Symbol]. That is, a derivation can be represented by a value of type [[Symbol]]. Represent the above derivation as a value of type [[Symbol]]. -} question5 = [ [Nonterminal "Exp"], [Terminal "(", Nonterminal "Op",Nonterminal "ExpList", Terminal ")"] , [Terminal "(", Terminal "+",Nonterminal "ExpList", Terminal ")"] , [Terminal "(", Terminal "+",Nonterminal "Exp", Nonterminal "ExpList", Terminal ")"] , [Terminal "(", Terminal "+",Terminal "1", Nonterminal "ExpList", Terminal ")"] , [Terminal "(", Terminal "+",Terminal "1", Nonterminal "Exp", Nonterminal "ExpList", Terminal ")"] , [Terminal "(", Terminal "+",Terminal "1", Terminal "2", Nonterminal "ExpList", Terminal ")"], [Terminal "(", Terminal "+",Terminal "1",Terminal "2", Terminal ")"] ]