www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 1b0179d0663e832744e6d2f24a692e854c62146b
parent 5c058bffd600475db357596202a9b0e98bbb5740
Author: Stephen Chang <stchang@ccs.neu.edu>
Date:   Thu, 28 May 2015 16:01:09 -0400

add sysf; fix begin splicing problem

Diffstat:
Mtapl/notes.txt | 22++++++++++++++++++++++
Mtapl/tests/ext-stlc-tests.rkt | 5+++++
Mtapl/tests/sysf-tests.rkt | 28++++++++++++++++++++++++++++
Mtapl/typecheck.rkt | 68++++++++++++++++++++++++++++++++++++--------------------------------
4 files changed, 91 insertions(+), 32 deletions(-)

diff --git a/tapl/notes.txt b/tapl/notes.txt @@ -1,3 +1,25 @@ +2015-05-28 +Problem: how to represent \forall types +1) (Racket) functions +- this gets the most linguistic reuse (is this true?) +- but this does not allow equality comparisons +- unless perhaps compare two foralls for equality by applying to the same tvar + - but these type vars would be unbound so it still wouldnt work without + adding a new special case +2) syntax +- easier to compare +- but still need to manually implement alpha equality +- would still require a special case for comparing the bodies, which have + unbound typevars + +Problem: begin in lambda body gets spliced +- results in combined syntax properties, eg types +Solution: +- wrap lambda body with #%expression to indicate expression, ie non-splicing, + begin + +Previous: ----------------- + macro system requirements: - depth-first expansion, i.e., localexpand, and stop-lists - language form hooks, e.g., #%app, etc diff --git a/tapl/tests/ext-stlc-tests.rkt b/tapl/tests/ext-stlc-tests.rkt @@ -21,6 +21,11 @@ (check-type (begin 1) : Int) (typecheck-fail (begin 1 2 3)) (check-type (begin (void) 1) : Int ⇒ 1) +(check-type ((λ ([x : Int]) (begin (void) x)) 1) : Int) +(check-type ((λ ([x : Int]) (begin x)) 1) : Int) +(check-type ((λ ([x : Int]) (begin (begin x))) 1) : Int) +(check-type ((λ ([x : Int]) (begin (void) (begin (void) x))) 1) : Int) +(check-type ((λ ([x : Int]) (begin (begin (void) x))) 1) : Int) ;;ascription (typecheck-fail (ann 1 : Bool)) diff --git a/tapl/tests/sysf-tests.rkt b/tapl/tests/sysf-tests.rkt @@ -2,6 +2,34 @@ (require "rackunit-typechecking.rkt") (check-type (inst (Λ (t) (λ ([x : t]) x)) Int) : (→ Int Int)) +(check-type (inst (Λ (t) 1) Bool) : Int) +; first inst should be discarded +(check-type (inst (inst (Λ (t) (Λ (t) (λ ([x : t]) x))) (→ Int Int)) Int) : (→ Int Int)) +; second inst is discarded +(check-type (inst (inst (Λ (t1) (Λ (t2) (λ ([x : t1]) x))) Int) (→ Int Int)) : (→ Int Int)) + +;; polymorphic arguments +(check-type (Λ (t) (λ ([x : t]) x)) : (∀ (t) (→ t t))) +(check-type (Λ (t) (λ ([x : t]) x)) : (∀ (s) (→ s s))) +(check-type (Λ (s) (Λ (t) (λ ([x : t]) x))) : (∀ (s) (∀ (t) (→ t t)))) +(check-type (Λ (s) (Λ (t) (λ ([x : t]) x))) : (∀ (r) (∀ (t) (→ t t)))) +(check-type (Λ (s) (Λ (t) (λ ([x : t]) x))) : (∀ (r) (∀ (s) (→ s s)))) +(check-type (Λ (s) (Λ (t) (λ ([x : t]) x))) : (∀ (r) (∀ (u) (→ u u)))) +(check-type (λ ([x : (∀ (t) (→ t t))]) x) : (→ (∀ (s) (→ s s)) (∀ (u) (→ u u)))) +(typecheck-fail ((λ ([x : (∀ (t) (→ t t))]) x) (λ ([x : Int]) x))) +(typecheck-fail ((λ ([x : (∀ (t) (→ t t))]) x) 1)) +(check-type ((λ ([x : (∀ (t) (→ t t))]) x) (Λ (s) (λ ([y : s]) y))) : (∀ (u) (→ u u))) +(check-type + (inst ((λ ([x : (∀ (t) (→ t t))]) x) (Λ (s) (λ ([y : s]) y))) Int) : (→ Int Int)) +(check-type + ((inst ((λ ([x : (∀ (t) (→ t t))]) x) (Λ (s) (λ ([y : s]) y))) Int) 10) + : Int ⇒ 10) +(check-type (λ ([x : (∀ (t) (→ t t))]) (inst x Int)) : (→ (∀ (t) (→ t t)) (→ Int Int))) +(check-type (λ ([x : (∀ (t) (→ t t))]) ((inst x Int) 10)) : (→ (∀ (t) (→ t t)) Int)) +(check-type ((λ ([x : (∀ (t) (→ t t))]) ((inst x Int) 10)) + (Λ (s) (λ ([y : s]) y))) + : Int ⇒ 10) + ;; previous tests ------------------------------------------------------------- (check-type 1 : Int) diff --git a/tapl/typecheck.rkt b/tapl/typecheck.rkt @@ -78,6 +78,7 @@ ;(printf "~a\n" τ) (or (string? (syntax-e τ)) (and (identifier? τ) (identifier-binding τ)) + (and (stx-pair? τ) (equal? '∀ (syntax->datum (stx-car τ)))) (and (stx-pair? τ) (stx-andmap is-type? τ)))) ;; ⊢ : Syntax Type -> Syntax ;; Attaches type τ to (expanded) expression e. @@ -89,26 +90,24 @@ [(b:typed-binding ...) #:with (x ...) #'(b.x ...) #:with (τ ...) #'(b.τ ...) - #:with - ;; if e is (begin e1 ...), (e1 ...) will be spliced into expanded λ - ;; (and begin will be dropped), so must handle that - (lam xs+ (lr-stxs+vs1 stxs1 vs1 (lr-stxs+vs2 stxs2 vs2 e_body+ ... e+))) - (expand/df - #`(λ (x ...) - (let-syntax ([x (make-rename-transformer (⊢ #'x #'τ))] ...) #,e))) + ;; wrap e with #%expression to prevent splicing begins into lambda body + #:with ((~literal #%plain-lambda) xs+ + (lr-stxs+vs1 stxs1 vs1 (lr-stxs+vs2 stxs2 vs2 + ((~literal #%expression) e+)))) + (expand/df + #`(λ (x ...) + (let-syntax ([x (make-rename-transformer (⊢ #'x #'τ))] ...) + (#%expression #,e)))) +;; print intermediate expansion -- for debugging ; #:with tmp ; (expand/df ; #`(λ (x ...) -; (let-syntax ([x (make-rename-transformer (⊢ #'x #'τ))] ...) #,e))) -; #:when (printf "~a\n" (syntax->datum #'tmp)) -; #:with (lam xs+ (lr-stxs+vs1 stxs1 vs1 (lr-stxs+vs2 stxs2 vs2 e+))) #'tmp - - ;; if e is (begin ...), types (ie syntax properties) of all begins - ;; will be accumulated on e+, so only get the first type - #:with τ_e (if (null? (syntax->list #'(e_body+ ...))) - (typeof #'e+) - (stx-car (typeof #'e+))) - (list #'xs+ #'(begin e_body+ ... e+) #'τ_e)] +; (let-syntax ([x (make-rename-transformer (⊢ #'x #'τ))] ...) +; (#%expression #,e)))) +; #:with ((~literal #%plain-lambda) xs+ +; (lr-stxs+vs1 stxs1 vs1 (lr-stxs+vs2 stxs2 vs2 +; ((~literal #%expression) e+)))) #'tmp + (list #'xs+ #'e+ (typeof #'e+))] [([x τ] ...) (infer/type-ctxt+erase #'([x : τ] ...) e)])) ; all xs are bound in the same scope (define (infers/type-ctxt+erase ctxt es) @@ -124,12 +123,9 @@ (list #'xs+ #'(e+ ...) (stx-map typeof #'(e+ ...)))] [([x τ] ...) (infers/type-ctxt+erase #'([x : τ] ...) es)])) - (define (infer+erase e [tvs #'()]) - (define e+ - (syntax-parse (expand/df #`(λ #,tvs #,e)) #:literals (#%expression) - [(lam tvs+ (#%expression e+)) #'e+] - [(lam tvs+ e+) #'e+])) - (list e+ (eval-τ (typeof e+) tvs))) + (define (infer+erase e) + (define e+ (expand/df e)) + (list e+ (eval-τ (typeof e+)))) (define (infer/tvs+erase e [tvs #'()]) (define-values (tvs+ e+) (syntax-parse (expand/df #`(λ #,tvs #,e)) #:literals (#%expression) @@ -138,9 +134,9 @@ (list tvs+ e+ (eval-τ (typeof e+) tvs))) (define (infers+erase es) (stx-map infer+erase es)) - (define (types=? τs1 τs2) + (define (types=? τs1 τs2 #:eval? [eval? #t]) (and (= (stx-length τs1) (stx-length τs2)) - (stx-andmap type=? τs1 τs2))) + (stx-andmap (λ (t1 t2) (type=? t1 t2 #:eval? eval?)) τs1 τs2))) (define (same-types? τs) (define τs-lst (syntax->list τs)) (or (null? τs-lst) @@ -185,21 +181,29 @@ ;; type=? : Type Type -> Boolean ;; Indicates whether two types are equal - (define (type=? τa τb) + (define (type=? τa τb #:eval? [eval? #t]) ;; expansion, and thus eval-τ is idempotent, ;; so should be ok to expand even if τa or τb are already expanded - (define τ1 (eval-τ τa)) - (define τ2 (eval-τ τb)) -; (printf "t1: ~a => ~a\n" (syntax->datum τa) (syntax->datum τ1)) -; (printf "t2: ~a => ~a\n" (syntax->datum τb) (syntax->datum τ2)) - (syntax-parse #`(#,τ1 #,τ2) +; (printf "t1: ~a => " (syntax->datum τa)) + (define τ1 (if eval? (eval-τ τa) τa)) +; (printf "~a\n" (syntax->datum τ1)) +; (printf "t2: ~a => " (syntax->datum τb)) + (define τ2 (if eval? (eval-τ τb) τb)) +; (printf "~a\n" (syntax->datum τ2)) + (syntax-parse #`(#,τ1 #,τ2) #:datum-literals (∀) ; → should not be datum literal; ; adding a type constructor should extend type equality ; #:datum-literals (→) [(x:id y:id) (free-identifier=? τ1 τ2)] [(s1:str s2:str) (string=? (syntax-e #'s1) (syntax-e #'s2))] + [((∀ (x ...) t1) (∀ (y ...) t2)) + #:when (= (stx-length #'(x ...)) (stx-length #'(y ...))) + #:with (z ...) (generate-temporaries #'(x ...)) + (type=? (substs #'(z ...) #'(x ...) #'t1) + (substs #'(z ...) #'(y ...) #'t2) + #:eval? #f)] [((τ1 ...) (τ2 ...)) - (types=? #'(τ1 ...) #'(τ2 ...))] + (types=? #'(τ1 ...) #'(τ2 ...) #:eval? eval?)] #;[((x ... → x_out) (y ... → y_out)) (and (type=? #'x_out #'y_out) (stx-andmap type=? #'(x ...) #'(y ...)))]