macrotypes/typed-lang-builder/examples/fomega.rkt
2016-06-28 13:22:58 -04:00

117 lines
4.3 KiB
Racket

#lang typed-lang-builder
(extends "sysf.rkt" #:except #%datum Λ inst)
(reuse String #%datum #:from "stlc+reco+var.rkt")
;; System F_omega
;; Type relation:
;; Types:
;; - types from sysf.rkt
;; - String from stlc+reco+var
;; Terms:
;; - extend ∀ Λ inst from sysf
;; - add tyλ and tyapp
;; - #%datum from stlc+reco+var
(define-syntax-category kind)
; want #%type to be equiv to★
; => edit current-kind? so existing #%type annotations (with no #%kind tag)
; are treated as kinds
; <= define ★ as rename-transformer expanding to #%type
(begin-for-syntax
(current-kind? (λ (k) (or (#%type? k) (kind? k))))
;; Try to keep "type?" backward compatible with its uses so far,
;; eg in the definition of λ or previous type constuctors.
;; (However, this is not completely possible, eg define-type-alias)
;; So now "type?" no longer validates types, rather it's a subset.
;; But we no longer need type? to validate types, instead we can use (kind? (typeof t))
(current-type? (λ (t)
(define k (typeof t))
#;(or (type? t) (★? (typeof t)) (∀★? (typeof t)))
(and ((current-kind?) k) (not (⇒? k))))))
; must override, to handle kinds
(provide define-type-alias)
(define-syntax define-type-alias
(syntax-parser
[(define-type-alias alias:id τ)
#:with (τ- k_τ) (infer+erase #'τ)
#:fail-unless ((current-kind?) #'k_τ) (format "not a valid type: ~a\n" (type->str #'τ))
#'(define-syntax alias (syntax-parser [x:id #'τ-] [(_ . rst) #'(τ- . rst)]))]))
(provide (for-syntax ★?))
(define-for-syntax ★? #%type?)
(define-syntax (make-rename-transformer #'#%type))
(define-kind-constructor #:arity >= 1)
(define-kind-constructor ∀★ #:arity >= 0)
(define-type-constructor #:bvs >= 0 #:arr ∀★)
;; alternative: normalize before type=?
; but then also need to normalize in current-promote
(begin-for-syntax
(define (normalize τ)
(syntax-parse τ #:literals (#%plain-app #%plain-lambda)
[x:id #'x]
[(#%plain-app
(#%plain-lambda (tv ...) τ_body) τ_arg ...)
(normalize (substs #'(τ_arg ...) #'(tv ...) #'τ_body))]
[(#%plain-lambda (x ...) . bodys)
#:with bodys_norm (stx-map normalize #'bodys)
(transfer-stx-props #'(#%plain-lambda (x ...) . bodys_norm) τ #:ctx τ)]
[(#%plain-app x:id . args)
#:with args_norm (stx-map normalize #'args)
(transfer-stx-props #'(#%plain-app x . args_norm) τ #:ctx τ)]
[(#%plain-app . args)
#:with args_norm (stx-map normalize #'args)
#:with res (normalize #'(#%plain-app . args_norm))
(transfer-stx-props #'res τ #:ctx τ)]
[_ τ]))
(define old-eval (current-type-eval))
(define (type-eval τ) (normalize (old-eval τ)))
(current-type-eval type-eval)
(define old-type=? (current-type=?))
; ty=? == syntax eq and syntax prop eq
(define (type=? t1 t2)
(let ([k1 (typeof t1)][k2 (typeof t2)])
(and (or (and (not k1) (not k2))
(and k1 k2 ((current-type=?) k1 k2)))
(old-type=? t1 t2))))
(current-type=? type=?)
(current-typecheck-relation (current-type=?)))
(define-typed-syntax Λ
[(Λ bvs:kind-ctx e)
[([bvs.x : bvs.kind tv-] ...) () [[e e-] : τ_e]]
--------
[ [[_ e-] : ( ([tv- : bvs.kind] ...) τ_e)]]])
(define-typed-syntax inst
[(inst e τ ...)
[ [[e e-] : (~∀ (tv ...) τ_body) ( : (~∀★ k ...))]]
[ [[τ τ-] : k] ...]
[#:with τ-inst (substs #'(τ- ...) #'(tv ...) #'τ_body)]
--------
[ [[_ e-] : τ-inst]]])
;; TODO: merge with regular λ and app?
;; - see fomega2.rkt
(define-typed-syntax tyλ
[(tyλ bvs:kind-ctx τ_body)
[() ([bvs.x : bvs.kind tv-] ...) [[τ_body τ_body-] : k_body]]
[#:fail-unless ((current-kind?) #'k_body)
(format "not a valid type: ~a\n" (type->str #'τ_body))]
--------
[ [[_ (λ- (tv- ...) τ_body-)] : ( bvs.kind ... k_body)]]])
(define-typed-syntax tyapp
[(tyapp τ_fn τ_arg ...)
[ [[τ_fn τ_fn-] : (~⇒ k_in ... k_out)]]
[#:fail-unless (stx-length=? #'[k_in ...] #'[τ_arg ...])
(num-args-fail-msg #'τ_fn #'[k_in ...] #'[τ_arg ...])]
[ [[τ_arg τ_arg-] : k_in] ...]
--------
[ [[_ (#%app- τ_fn- τ_arg- ...)] : k_out]]])