Guest User

Untitled

a guest
Apr 25th, 2018
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.23 KB | None | 0 0
  1. ;; The first three lines of this file were inserted by DrScheme. They record metadata
  2. ;; about the language level of this file in a form that our tools can easily process.
  3. (require (planet plai/plai:1:3))
  4. ;#reader(lib "reader.ss" "plai" "lang")
  5. ;;
  6. ;; Lecture XX : Type Checking
  7. ;;
  8.  
  9. ;------------------------------------------------------------------
  10. ; Note: The code in this file may be used as starter code for
  11. ; your assignment. But you must include a clear statement at the top
  12. ; of your file acknowledging the source and the extent of copying.
  13. ;
  14. ; E.g: "This code was based on the CS311 TFAE type checking
  15. ; code provided by Kris De Volder. We copied all the TFAE code
  16. ; except for the "type-check" function, which we rewrote from
  17. ; scratch."
  18.  
  19. ; Alternatively, you may simply develop your own code all from scratch
  20. ; and ommit this statement.
  21.  
  22. ; Remember that using code from anywhere (internet / lecture notes)
  23. ; without explicitly acknowledging the source is plagiarism.
  24. ;
  25. ; Using publically available code from anywhere *is* permitted *with*
  26. ; acknowledgement. However, if little of "your" code is actually written
  27. ; by you, then this may be reflected in your mark.
  28. ;
  29. ; For the CS311 assignment I recommend the following:
  30. ; - start from this code and use it as a general outline
  31. ; - fill in additional cases for parse / unparse as needed
  32. ; - add your own test cases.
  33. ; - !!!rewrite the code in "type-check" from scratch!!!!
  34. ;
  35. ; If you do this you will not loose marks for copying.
  36. ;
  37. ; In other words I recommend that you do NOT copy the "core" of the
  38. ; typechecker algorithm. Writing this yourself is the main point
  39. ; of doing the assignment.
  40. ;
  41. ; !!! If you decide to copy code from this file for your assignment,
  42. ; make sure it is clearly and explicitly stated whether you copied
  43. ; any of the code in the type-check function!!!!
  44. ;
  45. ; If you do copy the "type-check" code, you may loose marks (for
  46. ; not doing important portions of the assignment yourself).
  47. ; ------------------------------------------------------------------
  48.  
  49. ; In the book, and in the lectures so far, we have mainly considered
  50. ; how to write typing rules / judgements that formally define a
  51. ; type system.
  52.  
  53. ; How do we turn rules like these into a type-checker algorithm?
  54.  
  55. ; Today, let's consider this question and write ourselves a checker
  56. ; for a simple language: TFAE.
  57.  
  58. #|
  59. <TFAE> ::= <id>
  60. | true
  61. | false
  62. | <number>
  63. | {+ <TFAE> <TFAE>}
  64. | {- <TFAE> <TFAE>}
  65. | {* <TFAE> <TFAE>}
  66. | {izero <TFAE>}
  67. | {if <TFAE> <TFAE> <TFAE>}
  68. | {fun {<id> : <Type>} : <Type> <TFAE>}
  69. | {rec {<id> {fun {<id> : <Type>} : <Type> <TFAE>}} <TFAE>}
  70. | {with {<id> <expr>} <expr>}
  71. | {<TFAE> <TFAE>}
  72. | nempty
  73. | {ncons <TFAE> <TFAE>}
  74. | {nempty? <TFAE>}
  75. | {nfirst <TFAE>}
  76. | {nrest <TFAE>}
  77.  
  78. First let's recall the type-language (i.e. the BNF grammar
  79. that defines the types of our language).
  80.  
  81. <Type> ::= number
  82. | boolean
  83. | nlist
  84. | (<Type> -> <Type>)
  85.  
  86. TODO add additional cases
  87.  
  88. |#
  89.  
  90.  
  91. ; As usual, we will need a representation for abstract
  92. ; syntax trees for the expressions in our language.
  93. (define-type Exp
  94. (num (v number?))
  95. (bool (v boolean?))
  96. (id (name symbol?))
  97. (add (l Exp?) (r Exp?))
  98. (sub (l Exp?) (r Exp?))
  99. (mul (l Exp?) (r Exp?))
  100. (iszero (a Exp?))
  101. (is-nempty (a Exp?))
  102. (nfirst (a Exp?))
  103. (nrest (a Exp?))
  104. (iff (tst Exp?) (thn Exp?) (els Exp?))
  105. (fun (id symbol?) (arg-type Type?) (ret-type Type?) (body Exp?))
  106. (rec0 (id symbol?) (func fun?) (body Exp?))
  107. (with (id symbol?) (val Exp?) (body Exp?))
  108. (app (rator Exp?) (rand Exp?))
  109. (nempty)
  110. (nlist (l Exp?) (r Exp?)))
  111.  
  112. ; We will also need an AST representation for (parsed) types!
  113. (define-type Type
  114. (numT)
  115. (boolT)
  116. (nlistT)
  117. (funT (arg Type?) (ret Type?)))
  118.  
  119. ; and procedures to parse the concrete notations into ASTs
  120. (define (parse sexp)
  121. (cond ((memv sexp '(true false))
  122. (bool (eqv? sexp 'true)))
  123. ((eqv? sexp 'nempty)
  124. (nempty))
  125. ((symbol? sexp)
  126. (id sexp))
  127. ((number? sexp)
  128. (num sexp))
  129. ((pair? sexp)
  130. (case (car sexp)
  131. ((ncons) (apply nlist (map parse (cdr sexp))))
  132. ((if) (apply iff (map parse (cdr sexp))))
  133. ((+) (apply add (map parse (cdr sexp))))
  134. ((-) (apply sub (map parse (cdr sexp))))
  135. ((*) (apply mul (map parse (cdr sexp))))
  136. ((nempty?) (apply is-nempty (map parse (cdr sexp))))
  137. ((nfirst) (apply nfirst (map parse (cdr sexp))))
  138. ((nrest) (apply nrest (map parse (cdr sexp))))
  139. ((iszero) (apply iszero (map parse (cdr sexp))))
  140. ((with) ;{with {<id> <expr>} <expr>}
  141. (with (caar (cdr sexp))
  142. (parse (cadr (cadr sexp)))
  143. (parse (caddr sexp))))
  144. ((rec) ;{rec {<id> {fun {<id> : <Type>} : <Type> <TFAE>}} <TFAE>}
  145. (rec0 (caar (cdr sexp))
  146. (parse (cadr (cadr sexp)))
  147. (parse (caddr sexp))))
  148. ((fun) ;{fun {x : type} : type exp}
  149. (check! "Need : before arg-type decl" sexp (eq? ': (cadr (cadr sexp))))
  150. (check! "Need : before ret-type decl" sexp (eq? ': (caddr sexp)))
  151. (fun (car (cadr sexp))
  152. (parse-type (caddr (cadr sexp)))
  153. (parse-type (cadddr sexp))
  154. (parse (cadr (cdddr sexp)))))
  155. (else
  156. (apply app (map parse sexp)))))))
  157.  
  158. (define (check! message data bool)
  159. (if (not bool)
  160. (error message data)
  161. 'ok))
  162.  
  163. (define (parse-type sexp)
  164. (cond ((pair? sexp)
  165. (check! "Expect list of 3" sexp (= 3 (length sexp)))
  166. (check! "Expect arrow in second place" sexp (eq? '-> (cadr sexp)))
  167. (funT (parse-type (car sexp))
  168. (parse-type (caddr sexp))))
  169. (else
  170. (case sexp
  171. ((number) (numT))
  172. ((boolean) (boolT))
  173. ((list) (nlistT))
  174. (else
  175. (error "Syntax error in type" sexp))))))
  176.  
  177. ; - - - - - - ----------------------------------------------------------
  178.  
  179. ; To produce more readable error messages, let's implement some functions
  180. ; to convert (unparse) parsed internal representation of types and
  181. ; expressions back into their more readable external representations
  182. (define (unparse-type type)
  183. (type-case Type type
  184. (numT () 'number)
  185. (boolT () 'boolean)
  186. (nlistT () 'list)
  187. (funT (a r) `(,(unparse-type a) -> ,(unparse-type r)))))
  188.  
  189. (define (unparse x)
  190. (cond ((Type? x)
  191. (unparse-type x))
  192. ((Exp? x)
  193. (unparse-exp x))
  194. (else
  195. x)))
  196.  
  197. (define (unparse-exp exp)
  198. (type-case Exp exp
  199. (num (v) v)
  200. (bool (v) (if v 'true 'false))
  201. (id (name) name)
  202. (add (l r) `{+ ,(unparse l) ,(unparse r)})
  203. (sub (l r) `{- ,(unparse l) ,(unparse r)})
  204. (mul (l r) `{* ,(unparse l) ,(unparse r)})
  205. (nempty () `nempty)
  206. (nlist (l r) `{ncons ,(unparse l) ,(unparse r)})
  207. (iszero (a) `{iszero ,(unparse a)})
  208. (is-nempty (a) `{nempty? ,(unparse a)})
  209. (nfirst (a) `{nfirst ,(unparse a)})
  210. (nrest (a) `{nrest ,(unparse a)})
  211. (iff (tst thn els)
  212. `(if ,(unparse tst)
  213. ,(unparse thn)
  214. ,(unparse els)))
  215. (fun (id atype rtype body)
  216. `{fun {,id : ,(unparse atype)} : ,(unparse rtype)
  217. ,(unparse body)})
  218. (rec0 (id func body)
  219. `{rec {,id ,(unparse func)} ,(unparse body)})
  220. (with (id val body)
  221. `{with {,id ,(unparse val)} ,(unparse body)})
  222. (app (f a)
  223. `{,(unparse f) ,(unparse a)})))
  224.  
  225. ; -----------------------------------------------------------------------------
  226. ; Now let's implement the type checker. Based on the typing rules, which
  227. ; we will write on the board.
  228.  
  229.  
  230.  
  231.  
  232.  
  233.  
  234.  
  235.  
  236.  
  237.  
  238.  
  239.  
  240.  
  241.  
  242.  
  243.  
  244.  
  245.  
  246.  
  247.  
  248. ; We will need a representation for the type env "Gamma":
  249. (define-type Env
  250. (anEnv (id symbol?) (type Type?) (more Env?))
  251. (mtEnv))
  252.  
  253. ;We will write the type-checker in a style similar to
  254. ;the assignment. I've already set up a basic structure for this
  255. ;below.
  256.  
  257. ; type-of :: Exp Continuation<String> -> Type ... or error
  258. ; Returns either a Type (type checking passes)
  259. ; or signals an error by passing an error
  260. ; message String to the escape continuation.
  261. (define (type-of exp esc)
  262.  
  263. (define (err . args)
  264. (esc (apply format args)))
  265.  
  266. (define (lookup name env)
  267. (type-case Env env
  268. (mtEnv () (err "Unbound identifier: ~a" name))
  269. (anEnv (id tp more)
  270. (if (eq? id name) tp (lookup name more)))))
  271.  
  272. (define (check-equals! exp part expect got)
  273. (if (equal? expect got)
  274. 'ok
  275. (err "~a: ~a has type ~a but expected ~a"
  276. (unparse exp) (unparse part) (unparse got) (unparse expect))))
  277.  
  278. ; Exp Env -> Type (or error)
  279. ; rewrite
  280. (define (type-check exp env)
  281. (type-case Exp exp
  282. (nempty () (nlistT))
  283. (nlist (l r)
  284. (let ((l-type (type-check l env))
  285. (r-type (type-check r env)))
  286. (nlistT)))
  287. (num (v) (numT))
  288. (bool (v) (boolT))
  289. (add (l r)
  290. (let ((l-type (type-check l env))
  291. (r-type (type-check r env)))
  292. (check-equals! exp l (numT) l-type)
  293. (check-equals! exp r (numT) r-type)
  294. (numT)))
  295. (sub (l r)
  296. (let ((l-type (type-check l env))
  297. (r-type (type-check r env)))
  298. (check-equals! exp l (numT) l-type)
  299. (check-equals! exp r (numT) r-type)
  300. (numT)))
  301. (mul (l r)
  302. (let ((l-type (type-check l env))
  303. (r-type (type-check r env)))
  304. (check-equals! exp l (numT) l-type)
  305. (check-equals! exp r (numT) r-type)
  306. (numT)))
  307. (iszero (a)
  308. (begin (check-equals! exp a (numT) (type-check a env))
  309. (boolT)))
  310. (is-nempty (a)
  311. (begin (check-equals! exp a (nlistT) (type-check a env))
  312. (boolT)))
  313. (nfirst (a)
  314. (begin (check-equals! exp a (nlistT) (type-check a env))
  315. (type-check (nlist-l a) env)))
  316. (nrest (a)
  317. (begin (check-equals! exp a (nlistT) (type-check a env))
  318. (type-check (nlist-r a) env)))
  319. (id (name)
  320. (lookup name env))
  321. (iff (tst thn els)
  322. (let ((tst-t (type-check tst env))
  323. (thn-t (type-check thn env))
  324. (els-t (type-check els env)))
  325. (check-equals! exp tst (boolT) tst-t)
  326. (check-equals! exp els thn-t els-t)
  327. thn-t))
  328. (fun (a a-type r-type body)
  329. (let ((body-t (type-check body
  330. (anEnv a a-type env))))
  331. (check-equals! exp body r-type body-t)
  332. (funT a-type r-type)))
  333. (rec0 (id func body)
  334. (let ((f-type (type-check func
  335. (anEnv id (funT (fun-arg-type func) (fun-ret-type func)) env)))
  336. (b-type (type-check body
  337. (anEnv id (funT (fun-arg-type func) (fun-ret-type func)) env))))
  338. b-type))
  339. (with (id val body)
  340. (let* ((v-type (type-check val env))
  341. (b-type (type-check body (anEnv id v-type env))))
  342. b-type))
  343. (app (f a)
  344. (let ((f-type (type-check f env))
  345. (a-type (type-check a env)))
  346. (if (funT? f-type) 'ok
  347. (err "~a: ~a has type ~a but expected a function"
  348. (unparse exp) (unparse f) (unparse f-type)))
  349. (check-equals! exp a (funT-arg f-type) a-type)
  350. (funT-ret f-type)))))
  351.  
  352. ;Assignment specification says we should return an
  353. ;external representation of type, so call unparse!
  354. (unparse-type (type-check exp (mtEnv))))
  355.  
  356. ;-------------------------------------------------------------------------------------
  357. ; Tests for the parse function:
  358. ; Note these tests depend on the shape of the parse tree
  359. ; and the precise definition of AST types. So these test
  360. ; may not pass for student code (if, as is likely, AST reps are
  361. ; chosen a little differently)
  362.  
  363. (test (parse '4)
  364. (num 4))
  365. (test (parse 'true)
  366. (bool #t))
  367. (test (parse 'false)
  368. (bool #f))
  369. (test (parse '{+ 1 2})
  370. (add (num 1) (num 2)))
  371. (test (parse '{iszero 1})
  372. (iszero (num 1)))
  373. (test (parse '{if true 1 2})
  374. (iff (bool #t) (num 1) (num 2)))
  375. (test (parse 'x)
  376. (id 'x))
  377. (test (parse '{fun {x : number} : number {+ x 1}})
  378. (fun 'x (numT) (numT) (add (id 'x) (num 1))))
  379. (test (parse '{f x})
  380. (app (id 'f) (id 'x)))
  381.  
  382. (test (parse-type 'number)
  383. (numT))
  384. (test (parse-type 'boolean)
  385. (boolT))
  386. (test (parse-type '(number -> (number -> boolean)))
  387. (funT (numT) (funT (numT) (boolT))))
  388.  
  389. ;---- tests for the type checking --------------------------------------
  390.  
  391. (define *precise-errors* #t)
  392. ; set this to false to only check whether errors are generated, but
  393. ; not whether the message is matching.
  394. ; (should work for student code, even if error messages are not
  395. ; identical to ours).
  396.  
  397. ; We define the following to easily call "type-of" with
  398. ; an aproprate escaper continuation:
  399. (define (tc sexp)
  400. (let/cc k
  401. (type-of (parse sexp)
  402. (lambda (msg)
  403. (k (if *precise-errors*
  404. msg
  405. 'error))))))
  406.  
  407. ; Helper for testing: "normalizes" error messages
  408. ; to a single 'error value.
  409. (define (expect x)
  410. (if (string? x)
  411. (if *precise-errors* ;#f -> treat all messages as the same.
  412. x
  413. 'error)
  414. x))
  415.  
  416. (define-syntax tc-test
  417. (syntax-rules ()
  418. ((_ exp expected)
  419. (test (tc exp) (expect expected)))))
  420.  
  421. ;Numbers
  422. (tc-test '3 'number)
  423.  
  424. ;Booleans
  425. (tc-test 'true 'boolean)
  426. (tc-test 'false 'boolean)
  427.  
  428. ;Binary operator (what about number of operands???)
  429. (tc-test '{+ 3 4} 'number)
  430. (tc-test '{+ 3 {+ 2 4}} 'number)
  431. (tc-test '{+ true 4} "(+ true 4): true has type boolean but expected number")
  432. (tc-test '{+ 4 false} "(+ 4 false): false has type boolean but expected number")
  433.  
  434. ;Unary operator
  435. (tc-test '{iszero 0} 'boolean)
  436. (tc-test '{iszero false} "(iszero false): false has type boolean but expected number")
  437.  
  438. ;(Unbound) identifier
  439. (tc-test 'x "Unbound identifier: x")
  440.  
  441. ;If
  442. (tc-test '{if {+ 3 4} true true} "(if (+ 3 4) true true): (+ 3 4) has type number but expected boolean")
  443. (tc-test '{if true true true} 'boolean)
  444. (tc-test '{if false 1 2} 'number)
  445. (tc-test '{if false 1 true} "(if false 1 true): true has type boolean but expected number")
  446.  
  447. ; Fun and app
  448. (tc-test '{fun {x : number} : boolean {iszero {+ x -1}}} '(number -> boolean))
  449. (tc-test '{fun {x : boolean} : boolean {iszero {+ x -1}}}
  450. "(+ x -1): x has type boolean but expected number")
  451. (tc-test '{fun {x : number} : number {iszero {+ x -1}}}
  452. "(fun (x : number) : number (iszero (+ x -1))): (iszero (+ x -1)) has type boolean but expected number")
  453. (tc-test '{{fun {x : number} : boolean {iszero {+ x -1}}}
  454. 10}
  455. 'boolean)
  456. (tc-test '{{fun {x : number} : boolean {iszero {+ x -1}}}
  457. true}
  458. "((fun (x : number) : boolean (iszero (+ x -1))) true): true has type boolean but expected number")
  459. (tc-test '{1 2}
  460. "(1 2): 1 has type number but expected a function")
  461.  
  462. (tc-test '{rec {f {fun {x : number} : number {f {- x 1}}}} {f 5}} 'number)
  463. (tc-test '{with {val 5} {iszero val}} 'boolean)
Add Comment
Please, Sign In to add comment