fomega with kinds, no operator abstraction yet

This commit is contained in:
Stephen Chang 2015-06-11 16:46:50 -04:00
parent 7e9d8cd1e0
commit ef74f68270
7 changed files with 158 additions and 37 deletions

View File

@ -12,4 +12,4 @@ A file extends its immediate parent file.
- stlc+sub.rkt
- stlc+rec+sub.rkt (also pull in tup from stlc+var.rkt)
- sysf.rkt
- Fomega.rkt
- fomega.rkt

View File

@ -1,13 +1,117 @@
#lang racket/base
(require "typecheck.rkt")
(require (except-in "sysf.rkt" #%app)
(prefix-in stlc: (only-in "sysf.rkt" #%app)))
(provide (rename-out [stlc:#%app #%app]))
(provide (except-out (all-from-out "sysf.rkt") stlc:#%app))
(require (except-in "sysf.rkt" #%app λ + Λ inst Int eval-τ type=?)
(prefix-in sysf: (only-in "sysf.rkt" Int eval-τ type=?)))
(provide (rename-out [app/tc #%app] [λ/tc λ]))
(provide (except-out (all-from-out "sysf.rkt")
sysf:Int sysf:→ sysf:∀
(for-syntax sysf:type=? sysf:eval-τ)))
(provide Int inst Λ
(for-syntax eval-τ type=?))
;; System F_omega
;; Type relation:
;; Types:
;; - types from sysf.rkt
;; Terms:
;; - terms from sysf.rkt
(begin-for-syntax
;; Extend to handle ∀ with type annotations
(define (eval-τ τ [tvs #'()])
(syntax-parse τ
[((~literal ) (b:typed-binding ...) t-body)
#`( (b ...) #,((current-τ-eval) #'t-body (stx-append tvs #'(b.x ...))))]
;; need to manually handle type constructors now since they are macros
[((~literal ) t ...)
#`( #,@(stx-map (λ (ty) ((current-τ-eval) ty tvs)) #'(t ...)))]
[_ (sysf:eval-τ τ tvs)]))
(current-τ-eval eval-τ)
;; extend to handle ∀ with kind annotations
(define (type=? τ1 τ2)
(syntax-parse (list τ1 τ2) #:literals ()
[(( (a:typed-binding ...) t1:type) ( (b:typed-binding ...) t2:type))
#:when (= (stx-length #'(a ...)) (stx-length #'(b ...)))
#:with (z ...) (generate-temporaries #'(a ...))
#:when (typechecks? #'(a.τ ...) #'(b.τ ...))
((current-type=?) (substs #'(z ...) #'(a.x ...) #'t1)
(substs #'(z ...) #'(b.x ...) #'t2))]
[_ (sysf:type=? τ1 τ2)]))
(current-type=? type=?)
(current-typecheck-relation type=?))
(define-base-type )
(define-type-constructor )
;; for now, handle kind checking in the types themselves
;; TODO: move kind checking to a common place (like #%app)?
;; when expanding: check and erase kinds
(define-syntax Int (syntax-parser [x:id ( #'sysf:Int #')]))
;; → in Fω is not first-class, can't pass it around
(define-syntax ( stx)
(syntax-parse stx
[(_ τ ... τ_res)
#:with ([τ- k] ... [τ_res- k_res]) (infers+erase #'(τ ... τ_res))
#:when (typecheck? #'k_res #')
#:when (same-types? #'(k ... k_res))
( #'(sysf:→ τ- ... τ_res-) #')]))
(define-syntax ( stx)
(syntax-parse stx
[( (b:typed-binding ...) τ)
#:with (tvs- τ- k) (infer/type-ctxt+erase #'(b ...) #'τ)
#:when (typecheck? #'k #')
( #'(sysf:∀ tvs- τ-) #')]))
(define-syntax (Λ stx)
(syntax-parse stx
[(_ (b:typed-binding ...) e)
#:with ((tv- ...) e- τ) (infer/type-ctxt+erase #'(b ...) #'e)
( #'e- #'( ([tv- : b.τ] ...) τ))]))
(define-syntax (inst stx)
(syntax-parse stx
[(_ e τ ...)
#:with ([τ- k] ...) (infers+erase #'(τ ...))
#:with (e- τ_e) (infer+erase #'e)
#:with ((~literal ) (b:typed-binding ...) τ_body) #'τ_e
#:when (typechecks? #'(k ...) #'(b.τ ...))
( #'e- (substs #'(τ ...) #'(b.x ...) #'τ_body))]))
;; must override #%app and λ and primops to use new →
;; TODO: parameterize →?
(define-primop + : ( Int Int Int))
(define-syntax (λ/tc stx)
(syntax-parse stx
[(_ (b:typed-binding ...) e)
#:when (andmap ★? (stx-map (λ (t) (typeof (expand/df t))) #'(b.τ ...)))
#:with (xs- e- τ_res) (infer/type-ctxt+erase #'(b ...) #'e)
( #'(λ xs- e-) #'( b.τ ... τ_res))]))
(define-syntax (app/tc stx)
(syntax-parse stx #:literals ()
[(_ e_fn e_arg ...)
#:with (e_fn- ((~literal ) τ ... τ_res)) (infer+erase #'e_fn)
; #:fail-unless (→? #'τ_fn)
; (format "Type error: Attempting to apply a non-function ~a with type ~a\n"
; (syntax->datum #'e_fn) (syntax->datum #'τ_fn))
; #:with (→ τ ... τ_res) #'τ_fn
#:with ((e_arg- τ_arg) ...) (infers+erase #'(e_arg ...))
#:fail-unless (typechecks? #'(τ_arg ...) #'(τ ...))
(string-append
(format
"Wrong number of args given to function ~a, or args have wrong type:\ngiven: "
(syntax->datum #'e_fn))
(string-join
(map (λ (e+τ) (format "~a : ~a" (car e+τ) (cadr e+τ))) (syntax->datum #'([e_arg τ_arg] ...)))
", ")
"\nexpected arguments with type: "
(string-join
(map (λ (x) (format "~a" x)) (syntax->datum #'(τ ...)))
", "))
( #'(#%app e_fn- e_arg- ...) #'τ_res)]))

View File

@ -34,6 +34,8 @@
;; type equality = structurally recursive identifier equality
;; structurally checks for free-identifier=?
(define (type=? τ1 τ2)
; (printf "t1 = ~a\n" (syntax->datum τ1))
; (printf "t2 = ~a\n" (syntax->datum τ2))
(syntax-parse (list τ1 τ2)
[(x:id y:id) (free-identifier=? τ1 τ2)]
[((τa ...) (τb ...)) (types=? #'(τa ...) #'(τb ...))]

View File

@ -24,8 +24,6 @@
(begin-for-syntax
;; Extend to handle ∀, skip typevars
(define (eval-τ τ [tvs #'()])
; (printf "~a\n" (syntax->datum τ))
; (printf "tvs: ~a\n" tvs)
(syntax-parse τ
[x:id #:when (stx-member τ tvs) τ]
[((~literal ) ts t-body)
@ -47,7 +45,7 @@
;; extend to handle ∀
(define (type=? τ1 τ2)
(syntax-parse (list τ1 τ2) #:literals ()
[(( (x ...) t1) ( (y ...) t2))
[(( (x:id ...) t1) ( (y:id ...) t2))
#:when (= (stx-length #'(x ...)) (stx-length #'(y ...)))
#:with (z ...) (generate-temporaries #'(x ...))
((current-type=?) (substs #'(z ...) #'(x ...) #'t1)
@ -59,11 +57,12 @@
(define-syntax (Λ stx)
(syntax-parse stx
[(_ (tv:id ...) e)
#:with (tvs+ e- τ) (infer/tvs+erase #'e #'(tv ...))
( #'e- #'( tvs+ τ))]))
#:with (tvs- e- τ) (infer/tvs+erase #'e #'(tv ...))
( #'e- #'( tvs- τ))]))
(define-syntax (inst stx)
(syntax-parse stx
[(_ e τ ...)
#:with (e- τ_e) (infer+erase #'e)
#:with ((~literal ) (tv ...) τ_body) #'τ_e
( #'e- (substs #'(τ ...) #'(tv ...) #'τ_body))]))
#:with (τ+ ...) (stx-map (current-τ-eval) #'(τ ...))
( #'e- (substs #'(τ+ ...) #'(tv ...) #'τ_body))]))

View File

@ -1,42 +1,57 @@
#lang s-exp "../fomega.rkt"
(require "rackunit-typechecking.rkt")
(check-type (Λ (t1) (Λ (t2) (λ ([x : t1]) (λ ([y : t2]) y))))
: ( (t1) ( (t2) ( t1 ( t2 t2)))))
(check-type Int : )
(check-type ( Int Int) : )
(typecheck-fail ( ))
(check-type (Λ (t1) (Λ (t2) (λ ([x : t1]) (λ ([y : t2]) y))))
: ( (t3) ( (t4) ( t3 ( t4 t4)))))
(typecheck-fail (λ ([x : ( )]) x))
(check-not-type (Λ (t1) (Λ (t2) (λ ([x : t1]) (λ ([y : t2]) y))))
: ( (t4) ( (t3) ( t3 ( t4 t4)))))
(typecheck-fail ( (t) t)) ; missing kind annotation
(check-type ( ([t : ]) t) : )
(check-type ( ([ : ]) ) : ) ; should be ok
(check-type ( ([t : ]) ( ([s : ]) ( t s))) : )
(check-type ( ([t : ] [s : ]) ( t s)) : )
;(check-type (∀ ([t : (⇒ ★ ★)] [s : ★]) (t s)) : ★) ; doesnt work yet
(typecheck-fail ( (t) ( )))
(check-type (inst (Λ (t) (λ ([x : t]) x)) Int) : ( Int Int))
(check-type (inst (Λ (t) 1) Bool) : Int)
;; sysf tests wont work, must be augmented with kinds
(check-type (Λ ([t1 : ]) (Λ ([t2 : ]) (λ ([x : t1]) (λ ([y : t2]) y))))
: ( ([t1 : ]) ( ([t2 : ]) ( t1 ( t2 t2)))))
(check-type (Λ ([t1 : ]) (Λ ([t2 : ]) (λ ([x : t1]) (λ ([y : t2]) y))))
: ( ([t3 : ]) ( ([t4 : ]) ( t3 ( t4 t4)))))
(check-not-type (Λ ([t1 : ]) (Λ ([t2 : ]) (λ ([x : t1]) (λ ([y : t2]) y))))
: ( ([t4 : ]) ( ([t3 : ]) ( t3 ( t4 t4)))))
(check-type (inst (Λ ([t : ]) (λ ([x : t]) x)) Int) : ( Int Int))
(check-type (inst (Λ ([t : ]) 1) ( Int Int)) : Int)
; first inst should be discarded
(check-type (inst (inst (Λ (t) (Λ (t) (λ ([x : t]) x))) ( Int Int)) Int) : ( Int Int))
(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))
(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))))
(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 ((λ ([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))
(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)
((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)))
(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)

View File

@ -8,6 +8,7 @@
(check-type (λ ([x : Int] [y : Int]) x) : ( Int Int Int))
(check-not-type (λ ([x : Int]) x) : Int)
(check-type (λ ([x : Int]) x) : ( Int Int))
(check-type (λ ([x : ( )]) x) : ( ( ) ( ))) ; TODO: should this fail?
(check-type (λ ([f : ( Int Int)]) 1) : ( ( Int Int) Int))
(check-type ((λ ([x : Int]) x) 1) : Int 1)
(typecheck-fail ((λ ([x : Bool]) x) 1)) ; Bool is not valid type

View File

@ -11,7 +11,7 @@
: ( (t4) ( (t3) ( t3 ( t4 t4)))))
(check-type (inst (Λ (t) (λ ([x : t]) x)) Int) : ( Int Int))
(check-type (inst (Λ (t) 1) Bool) : Int)
(check-type (inst (Λ (t) 1) ( Int Int)) : Int)
; first inst should be discarded
(check-type (inst (inst (Λ (t) (Λ (t) (λ ([x : t]) x))) ( Int Int)) Int) : ( Int Int))
; second inst is discarded