



Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
A lecture on parsing types in programming languages, focusing on converting types from one language to another. The lecture covers the basics of parsing, including the definition of a parser and the use of operators like return and (>>=). The main goal is to create a parser for transforming types in a source language to a target language, which involves defining a typ parser and handling efficient parsing. The document also discusses the importance of parsing types in compilers and the need to associate compound types to the right.
Typology: Study notes
1 / 7
This page cannot be seen from the preview
Don't miss anything!




Our goal today is to have parsers which transform types in one language to another language. Specifically, we want ”(a → (b → c))” to be converted into ”(Arrow (T yV ar a)(Arrow (T yV ar b)(T yV ar c)))”. We plan to do the following:
Recall that parser type is defined as:
newT ype P arser a = M kP (String → [(a, String)])
In the previous lecture, we looked at the different ways of defining a type. Look at the notes or in the book, if you want more information. For all the parsers that we define in this lecture, most of them can be made from only two operators. return is defined as:
return :: a -> Parser a return v = MkP( i -> [(v,i)])
Parser1> apply (return 1) "abc" [(1,"abc")] :: [(Integer,String)]
The other operator is (>>=), called ”then” in Hutton’s book.
p >>= f MkP (\i -> case (apply p i) of [] -> [] [(v,out)] -> apply (f v) out
In general, parsers are built in the following fashion p 1 >>= λv 1 → p 2 >>= λv 2 → .. . pn >>= λvn → return (f v 1 v 2... vn) This notation is normally not used. Instead Haskell provides the do notation
do v 1 ← p 1 v 2 ← p 2 .. . v 3 ← pn return f v 1 v 2... vn
Let’s briefly review some of the parsers that Prof. Caldwell introduced last time.
item, which parses a string character by character
item:: Parser Char item = MkP(ı -> case i of [] -> [] (x:xs) -> [(x,xs)])
Next, we define a parser which reads the first three characters of a string and returns a pair of the first and the third character, and also returns the remaining string.
p :: Parser (Char,Char)
p = do x <- item item y <- item return (x,y)
Parser> apply p "xyzzy" [((’x’,’z’),"zy")] :: [((Char,Char),String)]
The two parsers can also be combined using the +++ (choice) operator.
typ::Parser Type typ = tyvar +++ arrow +++ prod
The typ parser is a ”choice” in the sense that we can either have a type variable or an arrow type or a product type. The tyvar, arrow, and prod parsers are defined as:
tyvar:: Parser Type tyvar = do n <- identifier return (TyVar n)
arrow::Parser Type arrow = do symbol "(" a <- typ symbol "-" symbol ">" b <- typ symbol ")" return (Arrow a b)
prod:: Parser Type prod = do symbol "(" a <- typ symbol "x" b <- typ symbol ")" return (Prod a b)
We can load this and check.
Parser1> apply typ "(a -> (b -> c))" [(Arrow (TyVar "a") (Arrow (TyVar "b") (TyVar "c")),[])] :: [(Type,String)] Parser1> apply typ "(a -> b -> c))" [] :: [(Type,String)] Parser1> apply typ "(a -> b -> c)" [] :: [(Type,String)] Parser1> apply typ "(a -> b) -> c" [(Arrow (TyVar "a") (TyVar "b"),"-> c")] :: [(Type,String)]
Note that we the parser takes care of extra spaces as shown below:
Parser1> apply typ "((a -> b ) -> c)" [(Arrow (Arrow (TyVar "a") (TyVar "b")) (TyVar "c"),[])] :: [(Type,String)] Parser1>
The parser so created is not an efficient parser. The inefficiency comes from the following code:
typ::Parser Type typ = tyvar +++ arrow +++ prod
To have an efficient parser, we change the code slightly. The new parser is:
typ::Parser Type typ = tyvar +++ comptype
comptype ::Parser Type comptype = do symbol "(" a <- typ constructor <- op c <- typ symbol ")" return (constructor a c)
op:: Parser (Type -> Type -> Type) op = arrow +++ prod
arrow ::Parser (Type -> Type -> Type) arrow = do symbol "->" return Arrow
prod::Parser (Type -> Type -> Type) prod = do symbol "x" return Prod
This doesn’t change the final output. For example,
Parser2> apply typ "((a -> b ) -> c)" [(Arrow (Arrow (TyVar "a") (TyVar "b")) (TyVar "c"),[])] :: [(Type,String)] Parser2>
Now we switch to a type language, where the compound types always asso- ciate to the right. So we can do away with the parens in our source language. The new grammar is given as:
type ::= string | type ” → ” type | type ” × ” type
The parser undergoes a slight modification.
[(Arrow (TyVar "a") (Arrow (Arrow (TyVar "b") (TyVar "c")) (Arrow (TyVar "d") (TyVar "e") Parser4> apply typ "a -> (b -> c -> d) -> e" [(Arrow (TyVar "a") (Arrow (Arrow (TyVar "b") (Arrow (TyVar "c") (TyVar "d"))) (TyVar "e" Parser4>