Add Typed Scheme as a collection.

svn: r8864

original commit: 0d54ed5e7427f5e75e6274cc3c9625e676fc34bc
This commit is contained in:
Sam Tobin-Hochstadt 2008-03-03 22:57:55 +00:00
commit 7f2824d11c
21 changed files with 2960 additions and 0 deletions

View File

@ -0,0 +1,4 @@
#lang setup/infotab
(define name "Typed Scheme")
(define scribblings '(("typed-scheme.scrbl")))

View File

@ -0,0 +1,9 @@
#lang s-exp "minimal.ss"
(providing (libs (except scheme/base require #%module-begin #%top-interaction with-handlers lambda #%app))
(basics #%module-begin
#%top-interaction
with-handlers
lambda
#%app)
(from scheme require))

View File

@ -0,0 +1,29 @@
#lang scheme/base
(provide #%module-begin provide require rename-in rename-out prefix-in only-in all-from-out except-out except-in
providing begin)
(require (for-syntax scheme/base))
(define-for-syntax ts-mod "../typed-scheme.ss")
(define-syntax (providing stx)
(syntax-case stx (libs from basics except)
[(form (libs (except lb ex ...) ...) (basics b ...) (from spec id ...) ...)
(datum->syntax
stx
(syntax->datum
(with-syntax ([(b* ...) (generate-temporaries #'(b ...))]
[ts ts-mod])
(syntax/loc
stx
(begin
(require (except-in ts b ...))
(require (only-in ts [b b*] ...))
(require (except-in lb ex ...) ...)
(require (only-in spec id ...) ...)
(provide id ...) ...
(provide (rename-out [b* b] ...))
(provide (all-from-out ts))
(provide (all-from-out lb) ...))))))]))

View File

@ -0,0 +1,15 @@
(module reader scheme/base
(require (prefix-in r: "../typed-reader.ss")
(only-in syntax/module-reader wrap-read-all))
(define (*read in)
(wrap-read-all 'typed-scheme/lang/main in r:read))
(define (*read-syntax src in)
(wrap-read-all 'typed-scheme/lang/main
in
(lambda (in)
(r:read-syntax src in))))
(provide (rename-out [*read read] [*read-syntax read-syntax])))

View File

@ -0,0 +1,570 @@
#lang scheme/base
(require (for-template (only-in (lib "list.ss") foldl)
scheme/base
'#%paramz
scheme/promise
string-constants/string-constant
#;'#%more-scheme
#;'#%qq-and-or
(lib "match-error.ss" "mzlib" "private" "match"))
)
(require
"extra-procs.ss"
scheme/promise
(except-in "type-rep.ss" make-arr)
(only-in scheme/list cons?)
"type-effect-convenience.ss"
(only-in "type-effect-convenience.ss" [make-arr* make-arr])
"union.ss"
string-constants/string-constant
(lib "match-error.ss" "mzlib" "private" "match")
"tc-structs.ss")
(require (for-syntax
scheme/base
"init-envs.ss"
(except-in "type-rep.ss" make-arr)
(only-in (lib "list.ss") foldl)
"type-effect-convenience.ss"
(only-in "type-effect-convenience.ss" [make-arr* make-arr])
"union.ss"
string-constants/string-constant
(lib "match-error.ss" "mzlib" "private" "match")
"tc-structs.ss"))
(define-for-syntax (initialize-others)
(d-s date
([second : N] [minute : N] [hour : N] [day : N] [month : N]
[year : N] [weekday : N] [year-day : N] [dst? : B] [time-zone-offset : N])
())
(d-s exn ([message : -String] [continuation-marks : Univ]) ())
(d-s (exn:fail exn) () (-String Univ))
(d-s (exn:fail:read exn:fail) ([srclocs : (-lst Univ)]) (-String Univ))
)
(provide (for-syntax initial-env initialize-others))
(define-for-syntax initial-env
(let ([make-lst make-Listof]
[make-lst/elements -pair])
(make-env
[string->sexpr (-> -String (-mu x (Un Sym -String N B (-lst x))))]
(car (make-Poly (list 'a 'b) (cl-> [((-pair (-v a) (-v b))) (-v a)]
[((make-lst (-v a))) (-v a)])))
[first (make-Poly (list 'a 'b) (cl-> [((-pair (-v a) (-v b))) (-v a)]
[((make-lst (-v a))) (-v a)]))]
[second (-poly (a b c)
(cl->
[((-pair a (-pair b c))) b]
[((-lst a)) a]))]
[third (-poly (a b c d)
(cl->
[((-pair a (-pair b (-pair c d)))) c]
[((-lst a)) a]))]
[fourth (-poly (a) ((-lst a) . -> . a))]
[fifth (-poly (a) ((-lst a) . -> . a))]
[sixth (-poly (a) ((-lst a) . -> . a))]
[rest (-poly (a) ((-lst a) . -> . (-lst a)))]
(cadr
(-poly (a b c)
(cl->
[((-pair a (-pair b c))) b]
[((-lst a)) a])))
(caddr (-poly (a) (-> (-lst a) a)))
(cadddr (-poly (a) (-> (-lst a) a)))
(cdr (make-Poly (list 'a 'b) (cl-> [((-pair (-v a) (-v b))) (-v b)]
[((make-lst (-v a))) (make-lst (-v a))])))
(cddr (make-Poly (list 'a) (-> (make-lst (-v a)) (make-lst (-v a)))))
(cdddr (make-Poly (list 'a) (-> (make-lst (-v a)) (make-lst (-v a)))))
(cons (-poly (a b)
(cl-> [(a (-lst a)) (-lst a)]
[(a b) (-pair a b)])))
[*cons (-poly (a b) (cl->
[(a b) (-pair a b)]
[(a (-lst a)) (-lst a)]))]
[*list? (make-pred-ty (-lst Univ))]
(null? (make-pred-ty (-val null)))
(eof-object? (make-pred-ty (-val eof)))
[null (-val null)]
(number? (make-pred-ty N))
(integer? (make-pred-ty -Integer))
(boolean? (make-pred-ty B))
(add1 (-> N N))
(sub1 (-> N N))
(eq? (-> Univ Univ B))
(eqv? (-> Univ Univ B))
(equal? (-> Univ Univ B))
(even? (-> N B))
[assert (-poly (a) (-> (*Un a (-val #f)) a))]
[gensym (cl-> [(Sym) Sym]
[() Sym])]
[string-append (->* null -String -String)]
[open-input-string (-> -String -Input-Port)]
[open-output-file
(cl->
[(-Pathlike) -Port]
[(-Pathlike Sym) -Port])]
[read (cl->
[(-Port) -Sexp]
[() -Sexp])]
[ormap (-poly (a b) ((-> a b) (-lst a) . -> . b))]
[andmap (-poly (a b) ((-> a b) (-lst a) . -> . b))]
[newline (cl-> [() -Void]
[(-Port) -Void])]
[not (-> Univ B)]
[floor (-> N N)]
[box (-poly (a) (a . -> . (make-Box a)))]
[unbox (-poly (a) ((make-Box a) . -> . a))]
[set-box! (-poly (a) ((make-Box a) a . -> . -Void))]
[box? (make-pred-ty (make-Box Univ))]
[cons? (make-pred-ty (-pair Univ Univ))]
[pair? (make-pred-ty (-pair Univ Univ)) #;(-poly (a b) (make-pred-ty (-pair a b)))]
[empty? (make-pred-ty (-val null))]
[empty (-val null)]
[string? (make-pred-ty -String)]
[string (->* '() -Char -String)]
[symbol? (make-pred-ty Sym)]
[list? (make-pred-ty (-lst Univ))]
[list (-poly (a) (->* '() a (-lst a)))]
[procedure? (make-pred-ty (make-Function (list (make-top-arr))))]
[map
(-poly (a b c d)
(cl-> [((-> a b) (-lst a)) (-lst b)]
[((-> a b c) (-lst a) (-lst b)) (-lst c)]
[((-> a b c d) (-lst a) (-lst b) (-lst c)) (-lst d)]))]
[for-each
(-poly (a b c)
(cl-> [((-> a b) (-lst a)) -Void]
[((-> a b c) (-lst a) (-lst b)) -Void]))]
[foldl (-poly (a b)
((a b . -> . b) b (make-lst a) . -> . b))]
[call-with-values (-poly (a b) (-> (-> a) (-> a b) b))]
(error
(make-Function (list
(make-arr null (Un))
(make-arr (list Sym -String) (Un) Univ)
(make-arr (list -String) (Un) Univ)
(make-arr (list Sym) (Un)))))
[namespace-variable-value
(cl->
[(Sym) Univ]
[(Sym B -Namespace (-> Univ)) Univ])]
(match:error (Univ . -> . (Un)))
(display
(cl->
[(Univ) -Void]
[(Univ -Port) -Void]))
[void (->* '() Univ -Void)]
[void? (make-pred-ty -Void)]
[printf (->* (list -String) Univ -Void)]
[fprintf (->* (list -Output-Port -String) Univ -Void)]
[format (->* (list -String) Univ -String)]
(fst (make-Poly (list 'a 'b) (-> (make-lst/elements (-v a) (-v b)) (-v a))))
(snd (make-Poly (list 'a 'b) (-> (make-lst/elements (-v a) (-v b)) (-v b))))
(= (->* (list N N) N B))
(>= (->* (list N N) N B))
(< (->* (list N N) N B))
(<= (->* (list N N) N B))
[> (->* (list N) N B)]
(zero? (N . -> . B))
(* (->* '() N N))
(/ (->* (list N) N N))
(+ (->* '() N N))
(- (->* (list N) N N))
(max (->* (list N) N N))
(min (->* (list N) N N))
[values (make-Poly '(a) (-> (-v a) (-v a)))]
[vector-ref
(make-Poly (list 'a) ((make-Vector (-v a)) N . -> . (-v a)))]
[build-vector (-poly (a) (N (N . -> . a) . -> . (make-Vector a)))]
[reverse (make-Poly '(a) (-> (make-lst (-v a)) (make-lst (-v a))))]
[append (-poly (a) (->* (list) (-lst a) (-lst a)))]
[length (make-Poly '(a) (-> (make-lst (-v a)) N))]
[memq (make-Poly (list 'a) (-> (-v a) (make-lst (-v a)) (-opt (make-lst (-v a)))))]
[memv (make-Poly (list 'a) (-> (-v a) (make-lst (-v a)) (-opt (make-lst (-v a)))))]
[member
(-poly (a) (a (-lst a) . -> . (-opt (-lst a))))]
[string<? (->* (list -String -String) -String B)]
[string>? (->* (list -String -String) -String B)]
[string=? (->* (list -String -String) -String B)]
[char=? (->* (list -Char -Char) -Char B)]
[string<=? (->* (list -String -String) -String B)]
[string>=? (->* (list -String -String) -String B)]
[string-ci<? (->* (list -String -String) -String B)]
[string-ci>? (->* (list -String -String) -String B)]
[string-ci=? (->* (list -String -String) -String B)]
[string-ci<=? (->* (list -String -String) -String B)]
[string-ci>=? (->* (list -String -String) -String B)]
[string-upcase (-> -String -String)]
[string-downcase (-> -String -String)]
[string-titlecase (-> -String -String)]
[string-foldcase (-> -String -String)]
[string-normalize-nfd (-> -String -String)]
[string-normalize-nfkd (-> -String -String)]
[string-normalize-nfc (-> -String -String)]
[string-normalize-nfkc (-> -String -String)]
[string-ref (-> -String N -Char)]
[substring (cl->*
(-> -String N -String)
(-> -String N N -String))]
[string->path (-> -String -Path)]
[file-exists? (-> -Pathlike B)]
[assq (-poly (a) (-> Univ (-lst (-pair Univ a)) a))]
[build-path ((list -Pathlike*) -Pathlike* . ->* . -Path)]
[string->number (-> -String (-opt N))]
[with-input-from-file
(-poly (a)
(cl->
[(-Pathlike (-> a)) a]
[(-Pathlike (-> a) Sym) a]))]
[with-output-to-file
(-poly (a)
(cl->
[(-Pathlike (-> a)) a]
[(-Pathlike (-> a) Sym) a]))]
[random (cl->
[(N) N]
[() N])]
[assoc (-poly (a b) (a (-lst (-pair a b)) . -> . (-opt (-pair a b))))]
[list-ref (-poly (a) ((-lst a) N . -> . a))]
[positive? (-> N B)]
[negative? (-> N B)]
[odd? (-> N B)]
[even? (-> N B)]
[apply (-poly (a b) (((list) a . ->* . b) (-lst a) . -> . b))]
[call/cc (-poly (a b) (((a . -> . (Un)) . -> . b) . -> . (*Un a b)))]
[call/ec (-poly (a b) (((a . -> . (Un)) . -> . b) . -> . (*Un a b)))]
[quotient (N N . -> . N)]
[remainder (N N . -> . N)]
[quotient/remainder (N N . -> . (-values (list N N)))]
;; parameter stuff
[parameterization-key Sym]
[extend-parameterization (-poly (a b) (-> Univ (-Param a b) a Univ))]
[continuation-mark-set-first (-> (-opt -Cont-Mark-Set) Univ Univ)]
[make-parameter (-poly (a b) (cl-> [(a) (-Param a a)]
[(b (a . -> . b)) (-Param a b)]))]
[current-directory (-Param -Pathlike -Path)]
[current-namespace (-Param -Namespace -Namespace)]
[print-struct (-Param B B)]
[read-decimal-as-inexact (-Param B B)]
[current-command-line-arguments (-Param (make-Vector -String) (make-Vector -String))]
;; regexp stuff
[regexp-match
(cl->
[((*Un -String -Regexp) -String) (-opt (-lst (-opt -String)))]
[(-Pattern -String) (-opt (-lst (-opt (*Un -Bytes -String))))]
[(-Pattern -String N) (-opt (-lst (-opt (*Un -Bytes -String))))]
[(-Pattern -String N (-opt N)) (-opt (-lst (-opt (*Un -Bytes -String))))]
[(-Pattern -String N (-opt N) (-opt -Output-Port)) (-lst (-opt (*Un -Bytes -String)))]
[(-Pattern -String (-opt N) (-opt -Output-Port)) (-lst (-opt (*Un -Bytes -String)))]
[(-Pattern -String (-opt -Output-Port)) (-lst (-opt (*Un -Bytes -String)))]
[(-Pattern (*Un -Input-Port -Bytes)) (-opt (-lst (-opt -Bytes)))]
[(-Pattern (*Un -Input-Port -Bytes) N) (-opt (-lst (-opt -Bytes)))]
[(-Pattern (*Un -Input-Port -Bytes) N (-opt N)) (-opt (-lst (-opt -Bytes)))]
[(-Pattern (*Un -Input-Port -Bytes) (-opt N)) (-opt (-lst (-opt -Bytes)))]
[(-Pattern (*Un -Input-Port -Bytes) N (-opt N) (-opt -Output-Port)) (-lst (-opt -Bytes))])]
[number->string (N . -> . -String)]
[current-milliseconds (-> N)]
[modulo (N N . -> . N)]
;; errors
[raise-type-error
(cl->
[(Sym -String Univ) (Un)]
[(Sym -String N (-lst Univ)) (Un)])]
;; this is a hack
[match:error ((list) Univ . ->* . (Un))]
[vector-set! (-poly (a) (-> (make-Vector a) N a -Void))]
[vector->list (-poly (a) (-> (make-Vector a) (-lst a)))]
[list->vector (-poly (a) (-> (-lst a) (make-Vector a)))]
[exact? (N . -> . B)]
[inexact? (N . -> . B)]
[expt (N N . -> . N)]
[vector (-poly (a) (->* (list) a (make-Vector a)))]
[real? (Univ . -> . B)]
[real-part (N . -> . N)]
[imag-part (N . -> . N)]
[magnitude (N . -> . N)]
[angle (N . -> . N)]
[numerator (N . -> . N)]
[denominator (N . -> . N)]
[exact->inexact (N . -> . N)]
[inexact->exact (N . -> . N)]
[make-string
(cl->
[(N) -String]
[(N -Char) -String])]
[arithmetic-shift (N N . -> . N)]
[abs (N . -> . N)]
[substring (cl-> [(-String N) -String]
[(-String N N) -String])]
[string-length (-String . -> . N)]
[string-set! (-String N -Char . -> . -Void)]
[make-vector
(-poly (a)
(cl->
[(N) (make-Vector N)]
[(N a) (make-Vector a)]))]
[file-exists? (-Pathlike . -> . B)]
[string->symbol (-String . -> . Sym)]
[symbol->string (Sym . -> . -String)]
[vector-length (-poly (a) ((make-Vector a) . -> . N))]
[call-with-input-file (-poly (a)
(cl->
[(-String (-Port . -> . a)) a]
[(-String (-Port . -> . a) Sym) a]))]
[call-with-output-file (-poly (a)
(cl->
[(-String (-Port . -> . a)) a]
[(-String (-Port . -> . a) Sym) a]))]
[current-output-port (-Param -Output-Port -Output-Port)]
[current-error-port (-Param -Output-Port -Output-Port)]
[current-input-port (-Param -Input-Port -Input-Port)]
[round (N . -> . N)]
[seconds->date (N . -> . (make-Struct 'date #f (list N N N N N N N N B N) #f))]
[current-seconds (-> N)]
[sqrt (-> N N)]
[path->string (-> -Path -String)]
[link-exists? (-> -Pathlike B)]
[directory-exists? (-> -Pathlike B)]
[file-exists? (-> -Pathlike B)]
[directory-list (cl-> [() (-lst -Path)]
[(-Path) (-lst -Path)])]
[make-hash-table (let ([ht-opt (*Un (-val 'weak) (-val 'equal))])
(-poly (a b)
(cl-> [() (-HT a b)]
[(ht-opt) (-HT a b)]
[(ht-opt ht-opt) (-HT a b)])))]
[hash-table-put! (-poly (a b) ((-HT a b) a b . -> . -Void))]
[hash-table-map (-poly (a b c) ((-HT a b) (a b . -> . c) . -> . (-lst c)))]
[hash-table-get (-poly (a b c)
(cl->
(((-HT a b) a) b)
(((-HT a b) a (-> c)) (*Un b c))
(((-HT a b) a c) (*Un b c))))]
#;[hash-table-index (-poly (a b) ((-HT a b) a b . -> . -Void))]
[bytes (->* (list) N -Bytes)]
[bytes-ref (-> -Bytes N N)]
[bytes-append (->* (list -Bytes) -Bytes -Bytes)]
[subbytes (cl->
[(-Bytes N) -Bytes]
[(-Bytes N N) -Bytes])]
[bytes-length (-> -Bytes N)]
[open-input-file (-> -Pathlike -Input-Port)]
[close-input-port (-> -Input-Port -Void)]
[close-output-port (-> -Output-Port -Void)]
[read-line (cl->
[() -String]
[(-Input-Port) -String]
[(-Input-Port Sym) -String])]
[copy-file (-> -Pathlike -Pathlike -Void)]
[bytes->string/utf-8 (-> -Bytes -String)]
;; language
[(expand #'(this-language))
Sym
string-constants/string-constant]
;; make-promise
[(cadr (syntax->list (expand #'(delay 3))))
(-poly (a) (-> (-> a) (-Promise a)))
scheme/promise]
;; qq-append
[(cadr (syntax->list (expand #'`(,@'() 1))))
(-poly (a b)
(cl->*
(-> (-lst a) (-val '()) (-lst a))
(-> (-lst a) (-lst b) (-lst (*Un a b)))))]
[force (-poly (a) (-> (-Promise a) a))]
[bytes<? (->* (list -Bytes) -Bytes B)]
[regexp-replace*
(cl->*
(-Pattern (*Un -Bytes -String) (*Un -Bytes -String) . -> . -Bytes)
(-Pattern -String -String . -> . -String))]
[peek-char
(cl->*
[-> -Char]
[-Input-Port . -> . -Char]
[-Input-Port N . -> . -Char]
[N . -> . -Char])]
[peek-byte
(cl->*
[-> -Byte]
[-Input-Port . -> . -Byte]
[-Input-Port N . -> . -Byte]
[N . -> . -Byte])]
[make-pipe
(cl->*
[-> (-values (list -Input-Port -Output-Port))]
[N . -> . (-values (list -Input-Port -Output-Port))])]
[open-output-bytes
(cl->*
[-> -Output-Port]
[Univ . -> . -Output-Port])]
[get-output-bytes
(cl->*
[-Output-Port . -> . -Bytes]
[-Output-Port Univ . -> . -Bytes]
[-Output-Port Univ N . -> . -Bytes]
[-Output-Port Univ N N . -> . -Bytes]
[-Output-Port N . -> . -Bytes]
[-Output-Port N N . -> . -Bytes])]
#;[exn:fail? (-> Univ B)]
#;[exn:fail:read? (-> Univ B)]
[write (-> -Sexp -Void)]
[open-output-string (-> -Output-Port)]
;; FIXME - wrong
[get-output-string (-> -Output-Port -String)]
[make-directory (-> -Path -Void)]
[hash-table-for-each (-poly (a b c)
(-> (-HT a b) (-> a b c) -Void))]
[delete-file (-> -Pathlike -Void)]
[make-namespace (cl->* (-> -Namespace)
(-> (*Un (-val 'empty) (-val 'initial)) -Namespace))]
[eval (-> -Sexp Univ)]
[exit (-> (Un))]
;; syntax operations
[syntax-source (-poly (a) (-> (-Syntax a) Univ))]
[syntax-position (-poly (a) (-> (-Syntax a) (-opt N)))]
[datum->syntax (cl->*
(-> (-opt (-Syntax Univ)) Sym (-Syntax Sym))
(-> (-opt (-Syntax Univ)) Univ (-Syntax Univ)))]
[syntax->datum (-poly (a) (-> (-Syntax a) Univ))]
[syntax-e (-poly (a) (-> (-Syntax a) a))]
[syntax-original? (-poly (a) (-> (-Syntax a) B))]
[identifier? (make-pred-ty (-Syntax Sym))]
[syntax? (make-pred-ty (-Syntax Univ))]
[syntax-property (-poly (a) (cl->* (-> (-Syntax a) Univ Univ (-Syntax a))
(-> (-Syntax Univ) Univ Univ)))]
)))
(begin-for-syntax (initialize-type-env initial-env)
(initialize-others))
;; the initial type name environment - just the base types
(define-syntax (define-tname-env stx)
(syntax-case stx ()
[(_ var provider [nm ty] ...)
#`(begin
(define-syntax nm (lambda (stx) (raise-syntax-error 'type-check "type name used out of context" stx))) ...
(provide nm) ...
(define-syntax provider (lambda (stx) #'(begin (provide nm) ...)))
(provide provider)
(begin-for-syntax
(initialize-type-name-env
(list (list #'nm ty) ...))))]))
(define-syntax (define-other-types stx)
(syntax-case stx ()
[(_ provider requirer nm ...)
(with-syntax ([(nms ...) (generate-temporaries #'(nm ...))])
(let ([body-maker (lambda (stx)
(map (lambda (nm nms) (datum->syntax stx `(rename ,#'mod ,nm ,nms)))
(syntax->list #'(nm ...))
(syntax->list #'(nms ...))))])
#'(begin (define-syntax nms (lambda (stx) (raise-syntax-error 'type-check "type name used out of context" stx))) ...
(provide nms) ...
(define-syntax (requirer stx)
(syntax-case stx ()
[(_ mod)
(datum->syntax
stx
`(require . ,(map (lambda (nm* nms*) (datum->syntax stx `(rename ,#'mod ,nm* ,nms*)))
(list 'nm ...)
(list #'nms ...))))]))
(define-syntax provider (lambda (stx) #'(begin (provide (rename-out [nms nm])) ...)))
(provide provider requirer))))]))
;; the initial set of available type names
(define-tname-env initial-type-names provide-tnames
[Number N]
[Integer -Integer]
[Void -Void]
[Boolean B]
[Symbol Sym]
[String -String]
[Any Univ]
[Port -Port]
[Path -Path]
[Regexp -Regexp]
[PRegexp -PRegexp]
[Char -Char]
[Option (-poly (a) (-opt a))]
[List (-lst Univ)]
[Listof -Listof]
[Namespace -Namespace]
[Input-Port -Input-Port]
[Output-Port -Output-Port]
[Bytes -Bytes]
[EOF (-val eof)]
[Keyword -Keyword]
[HashTable (-poly (a b) (-HT a b))]
[Promise (-poly (a) (-Promise a))]
[Pair (-poly (a b) (-pair a b))]
[Box (-poly (a) (make-Box a))]
[Syntax Any-Syntax]
[Identifier Ident]
)
(define-other-types
provide-extra-tnames
require-extra-tnames
-> U mu Un All Opaque Vectorof
Parameter Tuple Class
)
(provide-extra-tnames)

View File

@ -0,0 +1,9 @@
(module extra-procs mzscheme
(provide assert)
(define (assert v)
(unless v
(error "Assertion failed - value was #f"))
v)
)

View File

@ -0,0 +1,52 @@
(module mutated-vars mzscheme
(require-for-template mzscheme)
(require (lib "boundmap.ss" "syntax")
(lib "kerncase.ss" "syntax")
(lib "trace.ss"))
;; mapping telling whether an identifer is mutated
;; maps id -> boolean
(define table (make-module-identifier-mapping))
;; find and add to mapping all the set!'ed variables in form
;; syntax -> void
(define (find-mutated-vars form)
;; syntax -> void
(define (fmv/list lstx)
(for-each find-mutated-vars (syntax->list lstx)))
;(printf "called with ~a~n" (syntax-object->datum form))
(kernel-syntax-case* form #f (define-type-alias-internal define-typed-struct-internal require/typed-internal #%app lambda)
;; what we care about: set!
[(set! v e)
(begin
;(printf "mutated var found: ~a~n" (syntax-e #'v))
(module-identifier-mapping-put! table #'v #t))]
[(define-values (var ...) expr)
(find-mutated-vars #'expr)]
[(#%app . rest) (fmv/list #'rest)]
[(begin . rest) (fmv/list #'rest)]
[(begin0 . rest) (fmv/list #'rest)]
[(lambda _ . rest) (fmv/list #'rest)]
[(case-lambda (_ . rest) ...) (for-each fmv/list (syntax->list #'(rest ...)))]
[(if e1 e2) (begin (find-mutated-vars #'e1) (find-mutated-vars #'e2))]
[(if e1 e2 e3) (begin (find-mutated-vars #'e1) (find-mutated-vars #'e1) (find-mutated-vars #'e3))]
[(with-continuation-mark e1 e2 e3) (begin (find-mutated-vars #'e1)
(find-mutated-vars #'e1)
(find-mutated-vars #'e3))]
[(let-values ([_ e] ...) . b) (begin (fmv/list #'(e ...))
(fmv/list #'b))]
[(letrec-values ([_ e] ...) . b) (begin (fmv/list #'(e ...))
(fmv/list #'b))]
;; all the other forms don't have any expression subforms (like #%top)
[_ (void)]))
;(trace find-mutated-vars)
;; checks to see if a particular variable is ever set!'d
;; is-var-mutated? : identifier -> boolean
(define (is-var-mutated? id) (module-identifier-mapping-get table id (lambda _ #f)))
(provide find-mutated-vars is-var-mutated?)
)

View File

@ -0,0 +1,210 @@
#lang scheme/base
(provide parse-type parse-type/id)
(require (except-in "type-rep.ss" make-arr)
"type-effect-convenience.ss"
(only-in "type-effect-convenience.ss" [make-arr* make-arr])
"tc-utils.ss"
"union.ss"
(lib "stx.ss" "syntax")
(except-in "type-environments.ss")
"type-name-env.ss"
"type-alias-env.ss"
"type-utils.ss"
(only-in (lib "list.ss") foldl foldr)
#;(except-in (lib "list.ss" "srfi" "1") unfold remove)
(lib "plt-match.ss"))
(define enable-mu-parsing (make-parameter #t))
(define (parse-type/id loc datum)
#;(printf "parse-type/id id : ~a~n ty: ~a~n" (syntax-object->datum loc) (syntax-object->datum stx))
(let* ([stx* (datum->syntax loc datum loc loc)])
(parse-type stx*)))
(define (stx-cadr stx) (stx-car (stx-cdr stx)))
(define (parse-type stx)
(parameterize ([current-orig-stx stx])
(syntax-case* stx ()
symbolic-identifier=?
[(fst . rst)
(not (syntax->list #'rst))
(-pair (parse-type #'fst) (parse-type #'rst))]
[(Class (pos-args ...) ([fname fty . rest] ...) ([mname mty] ...))
(eq? (syntax-e #'Class) 'Class)
(make-Class
(map parse-type (syntax->list #'(pos-args ...)))
(map list
(map syntax-e (syntax->list #'(fname ...)))
(map parse-type (syntax->list #'(fty ...)))
(map (lambda (e) (syntax-case e ()
[(#t) #t]
[_ #f]))
(syntax->list #'(rest ...))))
(map list
(map syntax-e (syntax->list #'(mname ...)))
(map parse-type (syntax->list #'(mty ...)))))]
[(Instance t)
(eq? (syntax-e #'Instance) 'Instance)
(let ([v (parse-type #'t)])
(unless (or (Mu? v) (Class? v) (Union? v))
(tc-error "Argument to Instance must be a class type, got ~a" v))
(make-Instance v))]
[(Tuple ts ...)
(or (eq? (syntax-e #'Tuple) 'Tuple)
(eq? (syntax-e #'Tuple) 'List))
(begin
(add-type-name-reference (stx-car stx))
(-Tuple (map parse-type (syntax->list #'(ts ...)))))]
[(cons fst rst)
(eq? (syntax-e #'cons) 'cons)
(-pair (parse-type #'fst) (parse-type #'rst))]
[(pred t)
(eq? (syntax-e #'pred) 'pred)
(make-pred-ty (parse-type #'t))]
[(dom -> rng : pred-ty)
(and
(eq? (syntax-e #'->) '->)
(eq? (syntax-e #':) ':))
(begin
(add-type-name-reference (stx-cadr stx))
(make-pred-ty (list (parse-type #'dom)) (parse-type #'rng) (parse-type #'pred-ty)))]
[(dom ... rest ::: -> rng)
(and (eq? (syntax-e #'->) '->)
(or (symbolic-identifier=? #'::: (quote-syntax ..))
(symbolic-identifier=? #'::: (quote-syntax ...))))
(begin
(add-type-name-reference #'->)
(->* (map parse-type (syntax->list #'(dom ...))) (parse-type #'rest) (parse-type #'rng)))]
;; has to be below the previous one
[(dom ... -> rng)
(eq? (syntax-e #'->) '->)
(begin
(add-type-name-reference #'->)
(->* (map parse-type (syntax->list #'(dom ...))) (parse-type #'rng)))]
[(values tys ...)
(eq? (syntax-e #'values) 'values)
(-values (map parse-type (syntax->list #'(tys ...))))]
[(case-lambda tys ...)
(eq? (syntax-e #'case-lambda) 'case-lambda)
(make-Function (map (lambda (ty)
(syntax-case* ty (->) symbolic-identifier=?
[(dom ... -> rng)
(make-arr
(map parse-type (syntax->list #'(dom ...)))
(parse-type #'rng))]))
(syntax->list #'(tys ...))))]
;; I wish I could write this
#;[(case-lambda ([dom ... -> rng] ...)) (make-funty (list (make-arr (list (parse-type #'dom) ...) (parse-type #'rng)) ...))]
#;[(list-of t) (make-lst (parse-type #'t))]
#;[(Listof t) (make-lst (parse-type #'t))]
[(Vectorof t)
(eq? (syntax-e #'Vectorof) 'Vectorof)
(begin
(add-type-name-reference #'Vectorof)
(make-Vector (parse-type #'t)))]
[(mu x t)
(and (identifier? #'x)
(memq (syntax-e #'mu) '(mu Rec))
(enable-mu-parsing))
(let* ([var (syntax-e #'x)]
[tvar (make-F var)])
(add-type-name-reference #'mu)
(parameterize ([current-tvars (extend-env (list var) (list tvar) (current-tvars))])
(make-Mu var (parse-type #'t))))]
[(U ts ...)
(eq? (syntax-e #'U) 'U)
(begin
(add-type-name-reference #'U)
(apply Un (map parse-type (syntax->list #'(ts ...)))))]
[(Un-pat ts ...)
(eq? (syntax-e #'Un-pat) 'Un)
(apply Un (map parse-type (syntax->list #'(ts ...))))]
[(quot t)
(eq? (syntax-e #'quot) 'quote)
(-val (syntax-e #'t))]
[(All (vars ...) t)
(and (eq? (syntax-e #'All) 'All)
(andmap identifier? (syntax->list #'(vars ...))))
(let* ([vars (map syntax-e (syntax->list #'(vars ...)))]
[tvars (map make-F vars)])
(add-type-name-reference #'All)
(parameterize ([current-tvars (extend-env vars tvars (current-tvars))])
(make-Poly vars (parse-type #'t))))]
[(Opaque p?)
(eq? (syntax-e #'Opaque) 'Opaque)
(begin
(add-type-name-reference #'Opaque)
(make-Opaque #'p? (syntax-local-certifier)))]
[(Parameter t)
(eq? (syntax-e #'Parameter) 'Parameter)
(let ([ty (parse-type #'t)])
(add-type-name-reference #'Parameter)
(-Param ty ty))]
[(Parameter t1 t2)
(eq? (syntax-e #'Parameter) 'Parameter)
(begin
(add-type-name-reference #'Parameter)
(-Param (parse-type #'t1) (parse-type #'t2)))]
[id
(identifier? #'id)
(cond
;; if it's a type variable, we just produce the corresponding reference (which is in the HT)
[(lookup (current-tvars) (syntax-e #'id) (lambda (_) #f))]
;; if it's a type alias, we expand it (the expanded type is stored in the HT)
[(lookup-type-alias #'id parse-type (lambda () #f))
=>
(lambda (t)
(add-type-name-reference #'id)
t)]
;; if it's a type name, we just use the name
[(lookup-type-name #'id (lambda () #f))
(add-type-name-reference #'id)
(make-Name #'id)]
[else
(tc-error "unbound type ~a" (syntax-e #'id))])]
[(All . rest) (eq? (syntax-e #'All) 'All) (tc-error "All: bad syntax")]
[(Opaque . rest) (eq? (syntax-e #'Opaque) 'Opqaue) (tc-error "Opaque: bad syntax")]
[(U . rest) (eq? (syntax-e #'U) 'U) (tc-error "Union: bad syntax")]
[(Vectorof . rest) (eq? (syntax-e #'Vectorof) 'Vectorof) (tc-error "Vectorof: bad syntax")]
[(mu . rest) (eq? (syntax-e #'mu) 'mu) (tc-error "mu: bad syntax")]
[(Un . rest) (eq? (syntax-e #'Un) 'Un) (tc-error "Union: bad syntax")]
[(t ... -> . rest) (eq? (syntax-e #'->) '->) (tc-error "->: bad syntax")]
[(id arg args ...)
(let loop
([rator (parse-type #'id)]
[args (map parse-type (syntax->list #'(arg args ...)))])
(match rator
[(Name: _)
(make-App rator args stx)]
[(Poly: ns _)
(unless (= (length args) (length ns))
(tc-error "Wrong number of arguments to type ~a, expected ~a but got ~a" rator (length ns) (length args)))
(instantiate-poly rator args)]
[(Mu: _ _) (loop (unfold rator) args)]
[_ (tc-error "Type ~a cannot be applied, arguments were: ~a" rator args)]))
#;
(let ([ty (parse-type #'id)])
#;(printf "ty is ~a" ty)
(unless (Poly? ty)
(tc-error "not a polymorphic type: ~a" (syntax-e #'id)))
(unless (= (length (syntax->list #'(arg args ...))) (Poly-n ty))
(tc-error "wrong number of arguments to type constructor ~a: expected ~a, got ~a"
(syntax-e #'id)
(Poly-n ty)
(length (syntax->list #'(arg args ...)))))
(instantiate-poly ty (map parse-type (syntax->list #'(arg args ...)))))]
[t
(or (boolean? (syntax-e #'t)) (number? (syntax-e #'t))
(string? (syntax-e #'t)))
(-val (syntax-e #'t))]
[_ (tc-error "not a valid type: ~a" (syntax->datum stx))])))

View File

@ -0,0 +1,335 @@
#lang scheme/base
#|
This file defines two sorts of primitives. All of them are provided into any module using the typed scheme language.
1. macros for defining type annotated code.
this includes: lambda:, define:, etc
potentially, these macros should be replacements for the mzscheme ones in the user program
however, it's nice to be able to use both when the sugar is more limited
for example: (define ((f x) y) (+ x y))
2. macros for defining 'magic' code
examples: define-typed-struct, require/typed
these expand into (ignored) mzscheme code, and declarations that a typechecker understands
in order to protect the declarations, they are wrapped in `#%app void' so that local-expand of the module body
will not expand them on the first pass of the macro expander (when the stop list is ignored)
|#
(provide (all-defined-out))
(require (for-syntax
scheme/base
"type-rep.ss"
(lib "match.ss")
"parse-type.ss"
(lib "struct.ss" "syntax")
(lib "stx.ss" "syntax")
"utils.ss"
"tc-utils.ss"
"type-name-env.ss"
"type-contract.ss"))
(require "require-contract.ss"
"internal-forms.ss"
"planet-requires.ss"
(lib "etc.ss")
(except-in (lib "contract.ss") ->)
(only-in (lib "contract.ss") [-> c->])
(lib "struct.ss")
"base-env.ss")
(define-for-syntax (ignore stx) (syntax-property stx 'typechecker:ignore #t))
(define-for-syntax (internal stx)
(quasisyntax/loc stx
(define-values ()
(begin
(quote-syntax #,stx)
(#%plain-app values)))))
(define-syntax (require/typed stx)
(syntax-case* stx (rename) (lambda (x y) (eq? (syntax-e x) (syntax-e y)))
[(_ lib [nm ty] ...)
#'(begin (require/typed nm ty lib) ...)]
[(_ nm ty lib)
(identifier? #'nm)
(quasisyntax/loc stx (begin
#,(syntax-property (syntax-property #'(define cnt* #f)
'typechecker:contract-def #'ty)
'typechecker:ignore #t)
#,(internal #'(require/typed-internal nm ty))
#,(syntax-property #'(require/contract nm cnt* lib)
'typechecker:ignore #t)))]
[(_ (rename internal-nm nm) ty lib)
(raise-syntax-error "rename not currently supported" stx)
#; #;
(identifier? #'nm)
(quasisyntax/loc stx (begin
#,(syntax-property (syntax-property #'(define cnt* #f)
'typechecker:contract-def #'ty)
'typechecker:ignore #t)
#,(internal #'(require/typed-internal internal-nm ty))
#,(syntax-property #'(require/contract nm cnt* lib)
'typechecker:ignore #t)))]))
(define-syntax (require/opaque-type stx)
(syntax-case stx ()
[(_ ty pred lib)
(and (identifier? #'ty) (identifier? #'pred))
(begin
(register-type-name #'ty (make-Opaque #'pred (syntax-local-certifier)))
(quasisyntax/loc stx
(begin
#,(syntax-property #'(define pred-cnt (any/c . c-> . boolean?))
'typechecker:ignore #t)
#,(internal #'(require/typed-internal pred (Any -> Boolean : (Opaque pred))))
(define-type-alias ty (Opaque pred))
#,(syntax-property #'(require/contract pred pred-cnt lib)
'typechecker:ignore #t))))]))
(define-for-syntax (types-of-formals stx src)
(syntax-case stx (:)
[([var : ty] ...) (quasisyntax/loc stx (ty ...))]
[([var : ty] ... . [rest : rest-ty]) (syntax/loc stx (ty ... rest-ty ..))]
[_
(let loop ([stx stx])
(syntax-case stx ()
;; should never happen
[() (raise-syntax-error #f "bad annotation syntax" src stx)]
[([var : ty] . rest)
(identifier? #'var)
(loop #'rest)]
[([var : ty] . rest)
(raise-syntax-error #f "not a variable" src #'var)]
[(e . rest)
(raise-syntax-error #f "expected annotated variable of the form [x : T], got something else" src #'e)]))]))
(define-syntax (plambda: stx)
(syntax-case stx ()
[(plambda: (tvars ...) formals . body)
(syntax-property #'(lambda: formals . body)
'typechecker:plambda
#'(tvars ...))]))
(define-syntax (pcase-lambda: stx)
(syntax-case stx ()
[(pcase-lambda: (tvars ...) cl ...)
(syntax-property #'(case-lambda: cl ...)
'typechecker:plambda
#'(tvars ...))]))
(define-syntax (pdefine: stx)
(syntax-case stx (:)
[(pdefine: tvars (nm . formals) : ret-ty . body)
(with-syntax* ([(tys ...) (types-of-formals #'formals stx)]
[type (syntax/loc #'ret-ty (All tvars (tys ... -> ret-ty)))])
(syntax/loc stx
(define: nm : type
(plambda: tvars formals . body))))]))
(define-syntax (ann stx)
(syntax-case stx (:)
[(_ arg : ty)
#;#'(let: ([id : ty arg]) id)
(syntax-property #'arg 'type-ascription #'ty)]))
(define-syntax (: stx)
(let ([stx*
;; make it possible to add another colon after the id for clarity
(syntax-case stx (:)
[(: id : . more) (syntax/loc stx (: id . more))]
[_ stx])])
(syntax-case stx* ()
[(_ id ty)
(identifier? #'id)
(syntax-property
(internal (syntax/loc stx (:-internal id ty)))
'disappeared-use #'id)]
[(_ id ty)
(raise-syntax-error '|type declaration| "can only annotate identifiers with types"
stx #'id)]
[(_ _ _ _ . _)
(raise-syntax-error '|type declaration| "too many arguments" stx)]
[(_ _)
(raise-syntax-error '|type declaration| "too few arguments" stx)])))
(define-syntax (inst stx)
(syntax-case stx (:)
[(_ arg : tys ...)
(syntax-property #'arg 'type-inst #'(tys ...))]))
(define-syntax (define: stx)
(syntax-case stx (:)
[(define: (nm . formals) : ret-ty body ...)
(identifier? #'nm)
(with-syntax* ([(tys ...) (types-of-formals #'formals stx)]
[arrty (syntax/loc stx (tys ... -> ret-ty))])
(syntax/loc stx
(define: nm : arrty
(lambda: formals body ...))))]
[(define: nm : ty body)
(identifier? #'nm)
(with-syntax ([new-nm (syntax-property #'nm 'type-label #'ty)])
(syntax/loc stx (define new-nm body)))]
[(define: (vars ...) (f args ...) : ret body ...)
(andmap identifier? (syntax->list #'(vars ...)))
#'(pdefine: (vars ...) (f args ...) : ret body ...)]
[(define: (nm . formals) body ...)
(raise-syntax-error #f "missing return type annotation" stx)]
[(define: nm body)
(raise-syntax-error #f "missing type annotation" stx)]))
;; helper function for annoating the bound names
(define-for-syntax (annotate-names stx)
(define (label-one var ty)
(syntax-property var 'type-label ty))
(define (label vars tys)
(map label-one
(syntax->list vars)
(syntax->list tys)))
(syntax-case stx (:)
[[var : ty] (label-one #'var #'ty)]
[([var : ty] ...)
(label #'(var ...) #'(ty ...))]
[([var : ty] ... . [rest : rest-ty])
(append (label #'(var ...) #'(ty ...)) (label-one #'rest #'rest-ty))]))
(define-syntax-rule (λ: . args) (lambda: . args))
(define-syntax (lambda: stx)
(syntax-case stx (:)
[(lambda: formals . body)
(with-syntax ([labeled-formals (annotate-names #'formals)])
(syntax/loc stx (lambda labeled-formals . body)))]))
(define-syntax (case-lambda: stx)
(syntax-case stx (:)
[(case-lambda: [formals . body] ...)
(with-syntax ([(lab-formals ...) (map annotate-names (syntax->list #'(formals ...)))])
(syntax/loc stx (case-lambda [lab-formals . body] ...)))]))
(define-syntaxes (let-internal: let*: letrec:)
(let ([mk (lambda (form)
(lambda (stx)
(syntax-case stx (:)
[(_ ([nm : ty . exprs] ...) . body)
(with-syntax* ([(vars ...) (annotate-names #'([nm : ty] ...))]
[bindings (map (lambda (v e loc)
(quasisyntax/loc loc [#,v . #,e]))
(syntax->list #'(vars ...))
(syntax->list #'(exprs ...))
(syntax->list (syntax-case stx () [(_ bs . body) #'bs])))])
(quasisyntax/loc stx (#,form bindings . body)))])))])
(values (mk #'let) (mk #'let*) (mk #'letrec))))
(define-syntax (let: stx)
(syntax-case stx (:)
[(let: nm : ret-ty ([arg : ty val] ...) . body)
(identifier? #'nm)
(syntax/loc stx ((letrec: ([nm : (ty ... -> ret-ty) (lambda: ([arg : ty] ...) . body)]) nm) val ...))]
[(let: . rest)
(syntax/loc stx (let-internal: . rest))]))
(define-syntax (define-type-alias stx)
(syntax-case stx ()
[(_ tname rest)
(identifier? #'tname)
(begin
#`(begin
#,(ignore #'(define-syntax tname (lambda (stx) (raise-syntax-error 'type-check "type name used out of context" stx))))
#,(internal (syntax/loc stx (define-type-alias-internal tname rest)))))]
[(_ (tname . args) rest)
(andmap identifier? (syntax->list #'args))
#'(define-type-alias tname (All args rest))]))
(define-syntax (define-typed-struct/exec stx)
(syntax-case stx (:)
[(_ nm ([fld : ty] ...) [proc : proc-ty])
(with-syntax*
([proc* (syntax-property #'(ann proc : proc-ty) 'typechecker:with-type #t)]
[d-s (syntax-property (syntax/loc stx (define-struct/properties nm (fld ...)
([prop:procedure proc*])))
'typechecker:ignore-some #t)]
[dtsi (internal (syntax/loc stx (define-typed-struct/exec-internal nm ([fld : ty] ...) proc-ty)))])
#'(begin d-s dtsi))]))
(define-syntax (with-handlers: stx)
(syntax-case stx ()
[(_ ([pred? action] ...) . body)
(with-syntax ([(pred?* ...) (map (lambda (s) (syntax-property #`(ann #,s : (Any -> Any)) 'typechecker:with-type #t))
(syntax->list #'(pred? ...)))]
[(action* ...)
(map (lambda (s) (syntax-property s 'typechecker:exn-handler #t)) (syntax->list #'(action ...)))]
[body* (syntax-property #'(begin . body) 'typechecker:exn-body #t)])
(syntax-property #'(with-handlers ([pred?* action*] ...) body*)
'typechecker:with-handlers
#t))]))
(define-syntax (define-typed-struct stx)
(syntax-case stx (:)
[(_ nm ([fld : ty] ...) . opts)
(with-syntax ([d-s (syntax-property (syntax/loc stx (define-struct nm (fld ...) . opts))
'typechecker:ignore #t)]
[dtsi (internal (syntax/loc stx (define-typed-struct-internal nm ([fld : ty] ...))))])
#'(begin d-s dtsi))]
[(_ (vars ...) nm ([fld : ty] ...) . opts)
(with-syntax ([d-s (syntax-property (syntax/loc stx (define-struct nm (fld ...) . opts))
'typechecker:ignore #t)]
[dtsi (internal (syntax/loc stx (define-typed-struct-internal (vars ...) nm ([fld : ty] ...))))])
#'(begin d-s dtsi))]))
(define-syntax (require-typed-struct stx)
(syntax-case stx (:)
[(_ nm ([fld : ty] ...) lib)
(with-syntax* ([(struct-info maker pred sel ...) (build-struct-names #'nm (syntax->list #'(fld ...)) #f #t)]
[oty #'(Opaque pred)])
#'(begin
(require/opaque-type nm pred lib)
(require/typed maker (ty ... -> oty) lib)
(require/typed sel (oty -> ty) lib) ...))]))
(define-syntax (do: stx)
(syntax-case stx (:)
[(_ : ty ((var : tys init . step) ...) (e0 e1 ...) c ...)
(with-syntax ([(step ...)
(map (lambda (v s)
(syntax-case s ()
[() v]
[(e) #'e]
[_ (raise-syntax-error
#f
"bad variable syntax"
stx)]))
(syntax->list #'(var ...))
(syntax->list #'(step ...)))])
(syntax-case #'(e1 ...) ()
[() (syntax/loc
stx
(let: doloop : ty ([var : tys init] ...)
(if (not e0)
(begin c ... (doloop step ...)))))]
[(e1 e2 ...)
(syntax/loc
stx
(let: doloop : ty ([var : tys init] ...)
(if e0
(begin e1 e2 ...)
(begin c ... (doloop step ...)))))]))]))

View File

@ -0,0 +1,96 @@
#lang scheme/base
(require "type-rep.ss" "unify.ss" "union.ss" "infer.ss" "subtype.ss"
"type-utils.ss" "resolve-type.ss" "type-effect-convenience.ss"
mzlib/plt-match mzlib/trace)
(provide restrict (rename-out [*remove remove]) overlap)
(define (overlap t1 t2)
(match (list t1 t2)
[(list (Univ:) _) #t]
[(list _ (Univ:)) #t]
[(list (F: _) _) #t]
[(list _ (F: _)) #t]
[(list (Name: n) (Name: n*)) (free-identifier=? n n*)]
[(list (? Mu?) _) (overlap (unfold t1) t2)]
[(list _ (? Mu?)) (overlap t1 (unfold t2))]
[(list (Union: e) t)
(ormap (lambda (t*) (overlap t* t)) e)]
[(list t (Union: e))
(ormap (lambda (t*) (overlap t t*)) e)]
[(or (list _ (? Poly?)) (list (? Poly?) _))
#t] ;; these can have overlap, conservatively
[(list (Base: s1) (Base: s2)) (eq? s1 s2)]
[(list (Base: _) (Value: _)) (subtype t2 t1)] ;; conservative
[(list (Value: _) (Base: _)) (subtype t1 t2)] ;; conservative
[(list (Syntax: t) (Syntax: t*))
(overlap t t*)]
[(or (list (Syntax: _) _)
(list _ (Syntax: _)))
#f]
[(list (Base: _) _) #f]
[(list _ (Base: _)) #f]
[(list (Value: (? pair? v)) (Pair: _ _)) #t]
[(list (Pair: _ _) (Value: (? pair? v))) #t]
[(list (Pair: a b) (Pair: a* b*))
(and (overlap a a*)
(overlap b b*))]
[(or (list (Pair: _ _) _)
(list _ (Pair: _ _)))
#f]
[else #t]))
;; this is *definitely* not yet correct
;; NEW IMPL
;; restrict t1 to be a subtype of t2
(define (restrict t1 t2)
;; we don't use union map directly, since that might produce too many elements
(define (union-map f l)
(match l
[(Union: es)
(let ([l (map f es)])
;(printf "l is ~a~n" l)
(apply Un l))]))
(cond
[(subtype t1 t2) t1] ;; already a subtype
[(match t2
[(Poly: vars t)
(let ([subst (infer t t1 vars)])
(and subst (restrict t1 (subst-all subst t1))))]
[_ #f])]
[(Union? t1) (union-map (lambda (e) (restrict e t2)) t1)]
[(Mu? t1)
(restrict (unfold t1) t2)]
[(Mu? t2) (restrict t1 (unfold t2))]
[(subtype t2 t1) t2] ;; we don't actually want this - want something that's a part of t1
[(not (overlap t1 t2)) (Un)] ;; there's no overlap, so the restriction is empty
[else t2] ;; t2 and t1 have a complex relationship, so we punt
))
;(trace restrict)
;; also not yet correct
;; produces old without the contents of rem
(define (*remove old rem)
(define initial
(if (subtype old rem)
(Un) ;; the empty type
(match (list old rem)
[(list (or (App: _ _ _) (Name: _)) t)
;; must be different, since they're not subtypes
;; and n must refer to a distinct struct type
old]
[(list (Union: l) rem)
(apply Un (map (lambda (e) (*remove e rem)) l))]
[(list (? Mu? old) t) (*remove (unfold old) t)]
[(list (Poly: vs b) t) (make-Poly vs (*remove b rem))]
[_ old])))
(if (subtype old initial) old initial))
;(trace *remove)
;(trace restrict)

View File

@ -0,0 +1,40 @@
#lang scheme/base
(require scheme/contract (for-syntax scheme/base syntax/kerncase))
(provide require/contract define-ignored)
(define-syntax (define-ignored stx)
(syntax-case stx ()
[(_ name expr)
(syntax-case (local-expand/capture-lifts #'expr 'expression
(list #'define-values))
(begin define-values)
[(begin (define-values (n) e) e*)
#'(begin (define-values (n) e)
(define name e*))]
[e #'(define name e)])]))
(define-syntax (require/contract stx)
(syntax-case stx ()
[(require/contract nm cnt lib)
#`(begin (require (only-in lib [nm tmp]))
(define-ignored nm (contract cnt tmp '#,(syntax->datum #'nm) 'never-happen #'#,stx)))]))
#|
(module a mzscheme
(provide x)
(define (x a) 'hi))
(module z mzscheme
(require require-contract)
(require (lib "contract.ss"))
(define-struct b (X Y))
(require/contract x (b? . -> . b?) a )
(x 'no)
)
(require z)
|#

View File

@ -0,0 +1,79 @@
#lang scheme/base
(require "type-rep.ss" "type-name-env.ss" "tc-utils.ss"
"type-utils.ss"
mzlib/plt-match
mzlib/trace)
(provide resolve-name resolve-app needs-resolving? resolve-once)
(define (resolve-name t)
(match t
[(Name: n) (lookup-type-name n)]
[_ (int-err "resolve-name: not a name ~a" t)]))
(define (resolve-app rator rands stx)
(parameterize ([current-orig-stx stx])
(match rator
[(Poly: _ _)
(instantiate-poly rator rands)]
[(Name: _) (resolve-app (resolve-name rator) rands stx)]
[(Mu: _ _) (resolve-app (unfold rator) rands)]
[(App: r r* s) (resolve-app (resolve-app r r* s) rands)]
[_ (tc-error "resolve-app: not a proper operator ~a" rator)])))
(define (needs-resolving? t)
(or (Mu? t) (App? t) (Name? t)))
(define (resolve-once t)
(match t
[(Mu: _ _) (unfold t)]
[(App: r r* s) (resolve-app r r* s)]
[(Name: _) (resolve-name t)]))
#|
(define (resolve-tc-result tcr)
(match tcr
[(tc-result: t e1s e2s)
(ret (resolve-type t) (map resolve-effect e1s) (map resolve-effect e2s))]))
(define (resolve-effect* e)
(effect-case resolve-type resolve-effect e))
(define (resolve-type* t)
(define (int t)
(type-case resolve-type t
[#:Name stx (lookup-type-name stx)]
[#:Poly #:matcher Poly: names body (make-Poly names (resolve-type body))]
[#:Mu #:matcher Mu: name body (make-Mu name (resolve-type body))]
[#:App rator rands stx
(let ([rator (resolve-type rator)]
[rands (map resolve-type rands)])
(unless (Poly? rator)
(tc-error/stx stx "Cannot apply non-polymorphic type: ~a, arguments were: ~a" rator rands))
(instantiate-poly rator rands))]))
(let loop ([t (int t)])
(if (or (Name? t) (App? t))
(loop (resolve-type t))
t)))
(define table (make-hash-table))
(define (resolve-type t)
(hash-table-get table t
(lambda () (let ([v (resolve-type* t)])
(hash-table-put! table t v)
v))))
(define (resolve-effect t)
(hash-table-get table t
(lambda () (let ([v (resolve-effect* t)])
(hash-table-put! table t v)
v))))
;(trace resolve-type)
|#

View File

@ -0,0 +1,272 @@
#lang scheme/base
(require "type-rep.ss" "unify.ss" "type-utils.ss"
"tc-utils.ss"
"effect-rep.ss"
"type-comparison.ss"
"resolve-type.ss"
"type-name-env.ss"
mzlib/plt-match
mzlib/trace)
;; exn representing failure of subtyping
;; s,t both types
(define-struct (exn:subtype exn:fail) (s t))
#;
(define-values (fail-sym exn:subtype?)
(let ([sym (gensym)])
(values sym (lambda (s) (eq? s sym)))))
;; inference failure - masked before it gets to the user program
(define-syntax fail!
(syntax-rules ()
[(_ s t) #;(raise fail-sym)
(raise (make-exn:subtype "subtyping failed" (current-continuation-marks) s t))
#;(error "inference failed" s t)]))
;; data structures for remembering things on recursive calls
(define (empty-set) '())
(define current-seen (make-parameter (empty-set)))
(define (seen-before s t) (cons (Type-seq s) (Type-seq t)))
(define (remember s t A) (cons (seen-before s t) A))
(define (seen? s t) (member (seen-before s t) (current-seen)))
;; is s a subtype of t?
;; type type -> boolean
(define (subtype s t)
(with-handlers
([exn:subtype? (lambda _ #f)])
(subtype* (current-seen) s t)))
;; are all the s's subtypes of all the t's?
;; [type] [type] -> boolean
(define (subtypes s t)
(with-handlers
([exn:subtype? (lambda _ #f)])
(subtypes* (current-seen) s t)))
;; subtyping under constraint set, but produces boolean result instead of raising exn
;; List[(cons Number Number)] type type -> maybe[List[(cons Number Number)]]
(define (subtype*/no-fail A s t)
(with-handlers
([exn:subtype? (lambda _ #f)])
(subtype* A s t)))
;; type type -> (does not return)
;; subtying fails
#;
(define (fail! s t) (raise (make-exn:subtype "subtyping failed" (current-continuation-marks) s t)))
;; check subtyping for two lists of types
;; List[(cons Number Number)] listof[type] listof[type] -> List[(cons Number Number)]
(define (subtypes* A ss ts)
(cond [(and (null? ss) (null? ts) A)]
[(or (null? ss) (null? ts)) (fail! ss ts)]
[(subtype* A (car ss) (car ts))
=>
(lambda (A*) (subtypes* A* (cdr ss) (cdr ts)))]
[else (fail! (car ss) (car ts))]))
;; check if s is a supertype of any element of ts
(define (supertype-of-one/arr A s ts)
(ormap (lambda (e) (arr-subtype*/no-fail A e s)) ts))
(define (sub-eff e1 e2)
(match (list e1 e2)
[(list e e) #t]
[(list (Latent-Restrict-Effect: t) (Latent-Restrict-Effect: t*))
(and (subtype t t*)
(subtype t* t))]
[(list (Latent-Remove-Effect: t) (Latent-Remove-Effect: t*))
(and (subtype t t*)
(subtype t* t))]
[else #f]))
;(trace sub-eff)
;; simple co/contra-variance for ->
(define (arr-subtype*/no-fail A0 s t)
(with-handlers
([exn:subtype? (lambda _ #f)])
(match (list s t)
;; top for functions is above everything
[(list _ (top-arr:)) A0]
[(list (arr: s1 s2 #f thn-eff els-eff) (arr: t1 t2 #f (or '() thn-eff) (or '() els-eff)))
(let ([A1 (subtypes* A0 t1 s1)])
(subtype* A1 s2 t2))]
[(list (arr: s1 s2 s3 thn-eff els-eff) (arr: t1 t2 t3 thn-eff* els-eff*))
(unless
(or (and (null? thn-eff*) (null? els-eff*))
(and (effects-equal? thn-eff thn-eff*)
(effects-equal? els-eff els-eff*))
(and (andmap sub-eff thn-eff thn-eff*)
(andmap sub-eff els-eff els-eff*)))
(fail! s t))
;; either the effects have to be the same, or the supertype can't have effects
(let ([A (subtypes*/varargs A0 t1 s1 s3)])
(if (not t3)
(subtype* A s2 t2)
(let ([A1 (subtype* A t3 s3)])
(subtype* A1 s2 t2))))]
[else
(fail! s t)])))
(define (subtypes/varargs args dom rst)
(with-handlers
([exn:subtype? (lambda _ #f)])
(subtypes*/varargs (empty-set) args dom rst)))
(define (subtypes*/varargs A0 argtys dom rst)
(let loop-varargs ([dom dom] [argtys argtys] [A A0])
(cond
[(and (null? dom) (null? argtys)) A]
[(null? argtys) (fail! argtys dom)]
[(and (null? dom) rst)
(cond [(subtype* A (car argtys) rst) => (lambda (A) (loop-varargs dom (cdr argtys) A))]
[else (fail! (car argtys) rst)])]
[(null? dom) (fail! argtys dom)]
[(subtype* A (car argtys) (car dom)) => (lambda (A) (loop-varargs (cdr dom) (cdr argtys) A))]
[else (fail! (car argtys) (car dom))])))
;(trace subtypes*/varargs)
;; the algorithm for recursive types transcribed directly from TAPL, pg 305
;; List[(cons Number Number)] type type -> List[(cons Number Number)]
;; potentially raises exn:subtype, when the algorithm fails
;; is s a subtype of t, taking into account constraints A
(define (subtype* A s t)
(parameterize ([match-equality-test type-equal?]
[current-seen A])
(if (seen? s t)
A
(let* ([A0 (remember s t A)])
(parameterize ([current-seen A0])
#;(match t
[(Name: n) (when (eq? 'heap (syntax-e n))
(trace subtype*))]
[_ #f])
(match (list s t)
;; subtyping is reflexive
[(list t t) A0]
;; univ is top
[(list _ (Univ:)) A0]
;; (Un) is bot
[(list _ (Union: (list))) (fail! s t)]
[(list (Union: (list)) _) A0]
;; value types
[(list (Value: v1) (Value: v2)) (=> unmatch) (if (equal? v1 v2) A0 (unmatch))]
;; integers are numbers too
[(list (Base: 'Integer) (Base: 'Number)) A0]
;; values are subtypes of their "type"
[(list (Value: (? integer? n)) (Base: 'Integer)) A0]
[(list (Value: (? number? n)) (Base: 'Number)) A0]
[(list (Value: (? boolean? n)) (Base: 'Boolean)) A0]
[(list (Value: (? symbol? n)) (Base: 'Symbol)) A0]
[(list (Value: (? string? n)) (Base: 'String)) A0]
;; tvars are equal if they are the same variable
[(list (F: t) (F: t*)) (if (eq? t t*) A0 (fail! s t))]
;; case-lambda
[(list (Function: arr1) (Function: arr2))
(when (null? arr1) (fail! s t))
(let loop-arities ([A* A0]
[arr2 arr2])
(cond
[(null? arr2) A*]
[(supertype-of-one/arr A* (car arr2) arr1) => (lambda (A) (loop-arities A (cdr arr2)))]
[else (fail! s t)]))]
;; recur structurally on pairs
[(list (Pair: a d) (Pair: a* d*))
(let ([A1 (subtype* A0 a a*)])
(and A1 (subtype* A1 d d*)))]
;; quantification over two types preserves subtyping
[(list (Poly: ns b1) (Poly: ms b2))
(=> unmatch)
(unless (= (length ns) (length ms))
(unmatch))
;(printf "Poly: ~n~a ~n~a~n" b1 (subst-all (map list ms (map make-F ns)) b2))
(subtype* A0 b1 (subst-all (map list ms (map make-F ns)) b2))]
;; use unification to see if we can use the polytype here
[(list (Poly: vs b) s)
(=> unmatch)
(if (unify1 s b) A0 (unmatch))]
[(list s (Poly: vs b))
(=> unmatch)
(if (null? (fv b)) (subtype* A0 s b) (unmatch))]
;; names are compared for equality:
[(list (Name: n) (Name: n*))
(=> unmatch)
(if (free-identifier=? n n*)
A0
(unmatch))]
;; just unfold the recursive types
[(list _ (? Mu?)) (subtype* A0 s (unfold t))]
[(list (? Mu?) _) (subtype* A0 (unfold s) t)]
;; for unions, we check the cross-product
[(list (Union: es) t) (and (andmap (lambda (elem) (subtype* A0 elem t)) es) A0)]
[(list s (Union: es)) (and (ormap (lambda (elem) (subtype*/no-fail A0 s elem)) es) A0)]
;; subtyping on immutable structs is covariant
[(list (Struct: nm _ flds #f) (Struct: nm _ flds* #f))
(subtypes* A0 flds flds*)]
[(list (Struct: nm _ flds proc) (Struct: nm _ flds* proc*))
(subtypes* A0 (cons proc flds) (cons proc* flds*))]
;; subtyping on structs follows the declared hierarchy
[(list (Struct: nm (? Type? parent) flds proc) other)
;(printf "subtype - hierarchy : ~a ~a ~a~n" nm parent other)
(subtype* A0 parent other)]
;; applications and names are structs too
[(list (App: (Name: n) args _) other)
(let ([t (lookup-type-name n)])
(unless (Type? t)
(fail! s t))
#;(printf "subtype: app-name: name: ~a type: ~a other: ~a ~ninst: ~a~n" (syntax-e n) t other
(instantiate-poly t args))
(let ([v (subtype* A0 (instantiate-poly t args) other)])
#;(printf "val: ~a~n" v)
v))]
[(list (Name: n) other)
(let ([t (lookup-type-name n)])
;(printf "subtype: name: ~a ~a ~a~n" (syntax-e n) t other)
(if (Type? t)
(subtype* A0 t other)
(fail! s t)))]
;; Promises are covariant
[(list (Struct: 'Promise _ (list t) _) (Struct: 'Promise _ (list t*) _)) (subtype* A0 t t*)]
;; subtyping on values is pointwise
[(list (Values: vals1) (Values: vals2)) (subtypes* A0 vals1 vals2)]
;; single values shouldn't actually happen, but they're just like the type
[(list t (Values: (list t*))) (int-err "BUG - singleton values type~a" (make-Values (list t*)))]
[(list (Values: (list t)) t*) (int-err "BUG - singleton values type~a" (make-Values (list t)))]
;; subtyping on other stuff
[(list (Syntax: t) (Syntax: t*))
(subtype* A0 t t*)]
[(list (Instance: t) (Instance: t*))
(subtype* A0 t t*)]
;; otherwise, not a subtype
[_ (fail! s t) (printf "failed")]))))))
(define (type-compare? a b)
(and (subtype a b) (subtype b a)))
(provide subtype type-compare? subtypes/varargs subtypes)
;(trace subtype*)
;(trace supertype-of-one/arr)
;(trace arr-subtype*/no-fail)
;(trace subtype-of-one)
;(trace subtype*/no-fail)
;(trace subtypes*)
;(trace subtype)
;(subtype (-> Univ B) (-> Univ Univ))
;(subtype (make-poly '(a) (make-tvar 'a)) (make-lst N))

View File

@ -0,0 +1,92 @@
#lang scheme/base
(require "type-rep.ss" "parse-type.ss" "tc-utils.ss" "subtype.ss" "utils.ss" "union.ss" "resolve-type.ss"
"type-env.ss")
(require (lib "plt-match.ss"))
(provide type-annotation
get-type
get-type/infer
type-label-symbol
type-ascrip-symbol
check-type)
(define type-label-symbol 'type-label)
(define type-ascrip-symbol 'type-ascription)
(define (print-size stx)
(syntax-case stx ()
[(a . b) (begin
(printf/log "Annotation Sexp Pair ~n")
(print-size #'a)
(print-size #'b))]
[_ (printf/log "Annotation Sexp ~n" )]))
;; get the type annotation of this syntax
;; syntax -> Maybe[Type]
(define (type-annotation stx)
(define (pt prop)
(print-size prop)
(if (syntax? prop)
(parse-type prop)
(parse-type/id stx prop)))
(cond
[(syntax-property stx type-label-symbol) => pt]
[(syntax-property stx type-ascrip-symbol) => pt]
[(and (identifier? stx) (lookup-type stx (lambda () #f)))
=>
(lambda (t)
(maybe-finish-register-type stx)
t)]
[else #f]))
(define (log/ann stx ty)
(printf/log "Required Annotated Variable: ~a ~a~n" (syntax-e stx) ty))
(define (log/extra stx ty ty2)
(printf/log "Extra Annotated Variable: ~a ~a ~a~n" (syntax-e stx) ty ty2))
(define (log/noann stx ty)
(printf/log "Unannotated Variable: ~a ~a~n" (syntax-e stx) ty))
;; get the type annotation of this identifier, otherwise error
;; identifier -> Type
(define (get-type stx)
(parameterize
([current-orig-stx stx])
(cond
[(type-annotation stx) => (lambda (x)
(log/ann stx x)
x)]
[(not (syntax-original? stx))
(tc-error "untyped var: ~a" (syntax-e stx))]
[else
(tc-error "no type information on variable ~a" (syntax-e stx))])))
;; get the type annotations on this list of identifiers
;; if not all identifiers have annotations, return the supplied inferred type
;; list[identifier] type -> list[type]
(define (get-type/infer stxs e-type)
(match (list stxs e-type)
[(list '() (Values: '())) (list)]
[(list (list stx ...) (Values: (list ty ...)))
(map (lambda (stx ty)
(cond [(type-annotation stx) => (lambda (ann) (check-type stx ty ann) (log/extra stx ty ann) ann)]
[else (log/noann stx ty) ty]))
stx ty)]
[(list (list stx) ty)
(cond [(type-annotation stx) => (lambda (ann)
(check-type stx ty ann)
(log/extra stx ty ann)
(list ann))]
[else (log/noann stx ty) (list ty)])]
[else (int-err "wrong type arity - get-type/infer ~a ~a" stxs e-type)]))
;; check that e-type is compatible with ty in context of stx
;; otherwise, error
;; syntax type type -> void
(define (check-type stx e-type ty)
(let ([stx* (current-orig-stx)])
(parameterize ([current-orig-stx stx])
(unless (subtype e-type ty)
;(printf "orig-stx: ~a" (syntax->datum stx*))
(tc-error "Body had type:~n~a~nVariable had type:~n~a~n" e-type ty)))))

View File

@ -0,0 +1,231 @@
(module type-effect-convenience scheme/base
(require "type-rep.ss"
"effect-rep.ss"
mzlib/plt-match
"type-comparison.ss"
"type-effect-printer.ss"
"union.ss"
"subtype.ss"
"type-utils.ss"
(lib "list.ss")
scheme/promise
(prefix-in 1: srfi/1)
(for-syntax scheme/base))
(provide (all-defined-out))
(define (-vet id) (make-Var-True-Effect id))
(define (-vef id) (make-Var-False-Effect id))
(define -rem make-Remove-Effect)
(define -rest make-Restrict-Effect)
(define (var->type-eff eff)
(match eff
[(Var-True-Effect: v) (make-Remove-Effect (make-Value #f) v)]
[(Var-False-Effect: v) (make-Restrict-Effect (make-Value #f) v)]
[_ eff]))
(define ((add-var v) eff)
(match eff
[(Latent-Var-True-Effect:) (-vet v)]
[(Latent-Var-False-Effect:) (-vef v)]
[(Latent-Restrict-Effect: t) (make-Restrict-Effect t v)]
[(Latent-Remove-Effect: t) (make-Remove-Effect t v)]
[(True-Effect:) eff]
[(False-Effect:) eff]
[_ (error 'internal-tc-error "can't add var to effect ~a" eff)]))
(define-syntax ->
(syntax-rules (:)
[(_ dom ... rng)
(->* (list dom ...) rng)]
[(_ dom ... rng : eff1 eff2)
(->* (list dom ...) : eff1 eff2)]))
(define-syntax ->*
(syntax-rules (:)
[(_ dom rng)
(make-Function (list (make-arr* dom rng)))]
[(_ dom rst rng)
(make-Function (list (make-arr* dom rng rst)))]
[(_ dom rng : eff1 eff2)
(make-Function (list (make-arr* dom rng #f eff1 eff2)))]
[(_ dom rst rng : eff1 eff2)
(make-Function (list (make-arr* dom rng rst eff1 eff2)))]))
(define-syntax cl->
(syntax-rules (:)
[(_ [(dom ...) rng] ...)
(make-Function (list (make-arr* (list dom ...) rng) ...))]
[(_ [(dom ...) rng : eff1 eff2] ...)
(make-Function (list (make-arr* (list dom ...) rng #f eff1 eff2) ...))]
[(_ [(dom ...) rng rst : eff1 eff2] ...)
(make-Function (list (make-arr* (list dom ...) rng rst eff1 eff2) ...))]))
(define (cl->* . args)
(define (funty-arities f)
(match f
[(Function: as) as]))
(make-Function (map car (map funty-arities args))))
(define make-arr*
(case-lambda [(dom rng) (make-arr* dom rng #f (list) (list))]
[(dom rng rest) (make-arr dom rng rest (list) (list))]
[(dom rng rest eff1 eff2) (make-arr dom rng rest eff1 eff2)]))
(define (make-promise-ty t)
(make-Struct (string->uninterned-symbol "Promise") #f (list t) #f))
(define N (make-Base 'Number))
(define -Integer (make-Base 'Integer))
(define B (make-Base 'Boolean))
(define Sym (make-Base 'Symbol))
(define -Void (make-Base 'Void))
(define -Bytes (make-Base 'Bytes))
(define -Regexp (make-Base 'Regexp))
(define -PRegexp (make-Base 'PRegexp))
(define -Byte-Regexp (make-Base 'Byte-Regexp))
(define -Byte-PRegexp (make-Base 'Byte-PRegexp))
(define -String (make-Base 'String))
(define -Keyword (make-Base 'Keyword))
(define -Char (make-Base 'Char))
(define -Syntax make-Syntax)
(define -Prompt-Tag (make-Base 'Prompt-Tag))
(define -Cont-Mark-Set (make-Base 'Continuation-Mark-Set))
(define -Path (make-Base 'Path))
(define -Namespace (make-Base 'Namespace))
(define -Output-Port (make-Base 'Output-Port))
(define -Input-Port (make-Base 'Input-Port))
(define -HT make-Hashtable)
(define -Promise make-promise-ty)
(define Univ (make-Univ))
(define-syntax -v
(syntax-rules ()
[(_ x) (make-F 'x)]))
(define-syntax -poly
(syntax-rules ()
[(_ (vars ...) ty)
(let ([vars (-v vars)] ...)
(make-Poly (list 'vars ...) ty))]))
(define-syntax -mu
(syntax-rules ()
[(_ var ty)
(let ([var (-v var)])
(make-Mu 'var ty))]))
(define -values make-Values)
;; produce the appropriate type of a list of types
;; that is - if there is exactly one type, just produce it, otherwise produce a values-ty
;; list[type] -> type
(define (list->values-ty l)
(if (= 1 (length l)) (car l) (-values l)))
(define-syntax *Un
(syntax-rules ()
[(_ . args) (make-Union (list . args))]))
(define -pair make-Pair)
(define -base make-Base)
(define -struct make-Struct)
(define -val make-Value)
(define (make-Listof elem) (-mu list-rec (*Un (-val null) (-pair elem list-rec))))
(define -Listof (-poly (list-elem) (make-Listof list-elem)))
(define -lst make-Listof)
(define -Sexp (-mu x (*Un Sym N B -String (-val null) (-pair x x))))
(define -Port (*Un -Input-Port -Output-Port))
(define (-lst* . args) (if (null? args)
(-val null)
(-pair (car args) (apply -lst* (cdr args)))))
#;(define NE (-mu x (Un N (make-Listof x))))
(define -NE (-mu x (*Un N (-pair x (-pair Sym (-pair x (-val null)))))))
(define (Un/eff . args)
(apply Un (map tc-result-t args)))
(define -Param make-Param)
(define make-pred-ty
(case-lambda
[(in out t)
(->* in out : (list (make-Latent-Restrict-Effect t)) (list (make-Latent-Remove-Effect t)))]
[(t) (make-pred-ty (list Univ) B t)]))
(define -Pathlike (*Un -Path -String))
(define -Pathlike* (*Un (-val 'up) (-val 'same) -Path -String))
(define -Pattern (*Un -String -Bytes -Regexp -Byte-Regexp -PRegexp -Byte-PRegexp))
(define -Byte N)
(define (-Tuple l)
(foldr -pair (-val '()) l))
(define Any-Syntax
(-mu x
(-Syntax (*Un
(-lst x)
(-mu y (*Un x (-pair x y)))
(make-Vector x)
(make-Box x)
N
B
-String
Sym))))
(define Ident (-Syntax Sym))
;; DO NOT USE if t contains #f
(define (-opt t) (*Un (-val #f) t))
(define-syntax (make-env stx)
(syntax-case stx ()
[(_ e ...)
#`(list
#,@(map (lambda (e)
(syntax-case e ()
[(nm ty)
(identifier? #'nm)
#`(list #'nm ty)]
[(e ty extra-mods ...)
#'(list (let ([new-ns
(let* ([ns (make-empty-namespace)])
(namespace-attach-module (current-namespace)
'scheme/base
ns)
ns)])
(parameterize ([current-namespace new-ns])
(namespace-require 'extra-mods) ...
e))
ty)]))
(syntax->list #'(e ...))))]))
;; if t is of the form (Pair t* (Pair t* ... (Listof t*)))
;; return t*
;; otherwise, return t
;; generalize : Type -> Type
(define (generalize t)
(let/ec exit
(let loop ([t* t])
(match t*
[(Mu: var (Union: (list (Value: '()) (Pair: _ (F: var))))) t*]
[(Pair: t1 t2)
(let ([t-new (loop t2)])
(if (type-equal? (-lst t1) t-new)
t-new
(exit t)))]
[_ (exit t)]))))
)

View File

@ -0,0 +1,145 @@
(module type-effect-printer mzscheme
(require "type-rep.ss" "effect-rep.ss" "rep-utils.ss" "tc-utils.ss")
(require (lib "plt-match.ss"))
(require "planet-requires.ss")
;; do we attempt to find instantiations of polymorphic types to print?
;; FIXME - currently broken
(define print-poly-types? #f)
;; do we use simple type aliases in printing
(define print-aliases #t)
;; does t have a type name associated with it currently?
;; has-name : Type -> Maybe[Symbol]
(define (has-name? t)
(define ns ((current-type-names)))
(let/cc return
(unless print-aliases
(return #f))
(for-each
(lambda (pair)
(cond [(eq? t (cdr pair))
(return (car pair))]))
ns)
#f))
;; print out an effect
;; print-effect : Effect Port Boolean -> Void
(define (print-effect c port write?)
(define (fp . args) (apply fprintf port args))
(match c
[(Restrict-Effect: t v) (fp "(restrict ~a ~a)" t (syntax-e v))]
[(Remove-Effect: t v) (fp "(remove ~a ~a)" t (syntax-e v))]
[(Latent-Restrict-Effect: t) (fp "(restrict ~a)" t)]
[(Latent-Remove-Effect: t) (fp "(remove ~a)" t)]
[(Latent-Var-True-Effect:) (fp "(var #t)")]
[(Latent-Var-False-Effect:) (fp "(var #f)")]
[(True-Effect:) (fp "T")]
[(False-Effect:) (fp "F")]
[(Var-True-Effect: v) (fp "(var #t ~a)" (syntax-e v))]
[(Var-False-Effect: v) (fp "(var #f ~a)" (syntax-e v))]))
;; print out a type
;; print-type : Type Port Boolean -> Void
(define (print-type c port write?)
(define (fp . args) (apply fprintf port args))
(define (print-arr a)
(match a
[(top-arr:)
(fp "Procedure")]
[(arr: dom rng rest thn-eff els-eff)
(fp "(")
(for-each (lambda (t) (fp "~a " t)) dom)
(when rest
(fp "~a .. " rest))
(fp "-> ~a" rng)
(unless (and (null? thn-eff) (null? els-eff))
(fp " : ~a ~a" thn-eff els-eff))
(fp ")")]))
(define (tuple? t)
(match t
[(Pair: a (? tuple?)) #t]
[(Value: '()) #t]
[_ #f]))
(define (tuple-elems t)
(match t
[(Pair: a e) (cons a (tuple-elems e))]
[(Value: '()) null]))
;(fp "~a~n" (Type-seq c))
(match c
[(Univ:) (fp "Any")]
[(? has-name?) (fp "~a" (has-name? c))]
;; names are just the printed as the original syntax
[(Name: stx) (fp "[~a]" (syntax-e stx))]
[(App: rator rands stx)
(fp "~a" (cons rator rands))]
;; special cases for lists
[(Mu: var (Union: (list (Value: '()) (Pair: elem-ty (F: var)))))
(fp "(Listof ~a)" elem-ty)]
[(Mu: var (Union: (list (Pair: elem-ty (F: var)) (Value: '()))))
(fp "(Listof ~a)" elem-ty)]
[(Value: v) (cond [(or (symbol? v) (null? v))
(fp "'~a" v)]
[else (fp "~a" v)])]
[(? tuple? t)
(fp "~a" (cons 'List (tuple-elems t)))]
[(Base: n) (fp "~a" n)]
[(Opaque: pred _) (fp "(Opaque ~a)" (syntax-object->datum pred))]
[(Struct: 'Promise par (list fld) proc) (fp "(Promise ~a)" fld)]
[(Struct: nm par flds proc)
(fp "#(struct:~a ~a" nm flds)
(when proc
(fp " ~a" proc))
(fp ")")]
[(Function: arities)
(let ()
(match arities
[(list) (fp "(case-lambda)")]
[(list a) (print-arr a)]
[(list a ...) (fp "(case-lambda ") (for-each print-arr a) (fp ")")]))]
[(arr: _ _ _ _ _) (print-arr c)]
[(Vector: e) (fp "(Vectorof ~a)" e)]
[(Box: e) (fp "(Box ~a)" e)]
[(Union: elems) (fp "~a" (cons 'U elems))]
[(Pair: l r) (fp "(Pair ~a ~a)" l r)]
[(F: nm) (fp "<~a>" nm)]
[(Values: (list v ...)) (fp "~a" (cons 'values v))]
[(Param: in out)
(if (equal? in out)
(fp "(Paramter ~a)" in)
(fp "(Parameter ~a ~a)" in out))]
[(Hashtable: k v) (fp "(HashTable ~a ~a)" k v)]
#;
[(Poly-unsafe: n b) (fp "(unsafe-poly ~a ~a ~a)" (Type-seq c) n b)]
[(Poly-names: names body)
#;(fprintf (current-error-port) "POLY SEQ: ~a~n" (Type-seq body))
(fp "(All ~a ~a)" names body)]
#;
[(Mu-unsafe: b) (fp "(unsafe-mu ~a ~a)" (Type-seq c) b)]
[(Mu: x (Syntax: (Union: (list
(Base: 'Number)
(Base: 'Boolean)
(Base: 'Symbol)
(Base: 'String)
(Mu: var (Union: (list (Value: '()) (Pair: (F: x) (F: var)))))
(Mu: y (Union: (list (F: x) (Pair: (F: x) (F: y)))))
(Vector: (F: x))
(Box: (F: x))))))
(fp "SyntaxObject")]
[(Mu-name: name body) (fp "(mu ~a ~a ~a)" (Type-seq c) name body)]
;; FIXME - this should not be used
#;
[(Scope: sc) (fp "(Scope ~a)" sc)]
#;
[(B: idx) (fp "(B ~a)" idx)]
[(Syntax: t) (fp "(Syntax ~a)" t)]
[(Instance: t) (fp "(Instance ~a)" t)]
[(Class: pf nf ms) (fp "(Class)")]
[else (fp "Unknown Type: ~a" (struct->vector c))]
))
(set-box! print-type* print-type)
(set-box! print-effect* print-effect)
)

View File

@ -0,0 +1,78 @@
#lang scheme/base
(require "type-rep.ss"
"effect-rep.ss"
"tc-utils.ss"
"rep-utils.ss"
"free-variance.ss"
mzlib/plt-match
(for-syntax scheme/base))
(provide fv fv/list
substitute
subst-all
subst
ret
instantiate-poly
tc-result:
tc-result-equal?
effects-equal?
tc-result-t)
;; substitute : Type Name Type -> Type
(define (substitute image name target)
(define (sb t) (substitute image name t))
(if (hash-table-get (free-vars* target) name #f)
(type-case sb target
[#:F name* (if (eq? name* name) image target)])
target))
;; substitute many variables
;; substitution = Listof[List[Name,Type]]
;; subst-all : substition Type -> Type
(define (subst-all s t)
(foldr (lambda (e acc) (substitute (cadr e) (car e) acc)) t s))
(define (instantiate-poly t types)
(match t
[(Poly: ns body)
(unless (= (length types) (length ns))
(int-err "instantiate-poly: wrong number of types: expected ~a, got ~a" (length ns) (length types)))
(subst-all (map list ns types) body)]
[_ (int-err "instantiate-many: requires Poly type, got ~a" t)]))
;; this structure represents the result of typechecking an expression
(define-struct tc-result (t thn els) #:inspector #f)
(define-match-expander tc-result:
(lambda (stx)
(syntax-case stx ()
[(form pt) #'(struct tc-result (pt _ _))]
[(form pt pe1 pe2) #'(struct tc-result (pt pe1 pe2))])))
;; convenience function for returning the result of typechecking an expression
(define ret
(case-lambda [(t) (make-tc-result t (list) (list))]
[(t thn els) (make-tc-result t thn els)]))
(define (subst v t e) (substitute t v e))
;; type comparison
;; equality - good
(define tc-result-equal? equal?)
(define (effects-equal? fs1 fs2) (andmap eq? fs1 fs2))
;; fv : Type -> Listof[Name]
(define (fv t) (hash-table-map (free-vars* t) (lambda (k v) k)))
;; fv/list : Listof[Type] -> Listof[Name]
(define (fv/list ts) (hash-table-map (combine-frees (map free-vars* ts)) (lambda (k v) k)))

View File

@ -0,0 +1,62 @@
(module union mzscheme
(require "type-rep.ss" "subtype.ss" "tc-utils.ss"
"type-effect-printer.ss" "rep-utils.ss"
"type-comparison.ss")
(require (lib "plt-match.ss") (lib "list.ss") (lib "trace.ss"))
(provide Un #;(rename *Un Un))
(define (make-union* set)
(match set
[(list t) t]
[_ (make-Union set)]))
(define empty-union (make-Union null))
(define (flat t)
(match t
[(Union: es) es]
[_ (list t)]))
#;(define (Values-types t) (match t [(Values: ts) ts]))
(define (remove-subtypes ts)
(let loop ([ts* ts] [result '()])
(cond [(null? ts*) (reverse result)]
[(ormap (lambda (t) (subtype (car ts*) t)) result) (loop (cdr ts*) result)]
[else (loop (cdr ts*) (cons (car ts*) result))])))
(define Un
(case-lambda
[() empty-union]
[args
;; a is a Type (not a union type)
;; b is a List[Type]
(define (union2 a b)
(define b* (make-union* b))
(cond
[(subtype a b*) (list b*)]
[(subtype b* a) (list a)]
[else (cons a b)]))
#;(union-count!)
(let ([types (remove-dups (sort (apply append (map flat args)) type<?))])
(cond
[(null? types) (make-union* null)]
[(null? (cdr types)) (car types)]
[(ormap Values? types)
(if (andmap Values? types)
(make-Values (apply map Un (map Values-types types)))
(int-err "Un: should not take the union of multiple values with some other type: ~a" types))]
[else (make-union* #;(remove-subtypes types) (foldr union2 null types))]))]))
#;(defintern (Un-intern args) (lambda (_ args) (apply Un args)) args)
#;(define (*Un . args) (Un-intern args))
;(trace Un)
(define (u-maker args) (apply Un args))
;(trace u-maker)
(set-union-maker! u-maker)
)

View File

@ -0,0 +1,90 @@
(module typed-reader mzscheme
(require (lib "etc.ss"))
(require-for-template "private/prims.ss")
;; Provides raise-read-error and raise-read-eof-error
(require (lib "readerr.ss" "syntax"))
(define (skip-whitespace port)
;; Skips whitespace characters, sensitive to the current
;; readtable's definition of whitespace
(let ([ch (peek-char port)])
(unless (eof-object? ch)
;; Consult current readtable:
(let-values ([(like-ch/sym proc dispatch-proc)
(readtable-mapping (current-readtable) ch)])
;; If like-ch/sym is whitespace, then ch is whitespace
(when (and (char? like-ch/sym)
(char-whitespace? like-ch/sym))
(read-char port)
(skip-whitespace port))))))
(define (skip-comments read-one port src)
;; Recursive read, but skip comments and detect EOF
(let loop ()
(let ([v (read-one)])
(cond
[(special-comment? v) (loop)]
[(eof-object? v)
(let-values ([(l c p) (port-next-location port)])
(raise-read-eof-error "unexpected EOF in type annotation" src l c p 1))]
[else v]))))
(define (parse port read-one src)
(skip-whitespace port)
(let ([name (read-one)])
(begin0
(begin (skip-whitespace port)
(let ([next (read-one)])
(case (syntax-e next)
;; type annotation
[(:) (skip-whitespace port)
(syntax-property name 'type-label (syntax-object->datum (read-one)))]
[(::) (skip-whitespace port)
(datum->syntax-object name `(ann ,name : ,(read-one)))]
[(@) (let ([elems (let loop ([es '()])
(skip-whitespace port)
(if (equal? #\} (peek-char port))
(reverse es)
(loop (cons (read-one) es))))])
(datum->syntax-object name `(inst ,name : ,@elems)))]
;; arbitrary property annotation
[(PROP) (skip-whitespace port)
(let* ([prop-name (syntax-e (read-one))])
(skip-whitespace port)
(syntax-property name prop-name (read-one)))]
;; type annotation
[else (syntax-property name 'type-label (syntax-object->datum next))])))
(skip-whitespace port)
(let ([c (read-char port)])
#;(printf "char: ~a" c)
(unless (equal? #\} c)
(let-values ([(l c p) (port-next-location port)])
(raise-read-error (format "typed expression ~a not properly terminated" (syntax-object->datum name)) src l c p 1)))))))
(define parse-id-type
(case-lambda
[(ch port src line col pos)
;; `read-syntax' mode
(datum->syntax-object
#f
(parse port
(lambda () (read-syntax src port ))
src)
(let-values ([(l c p) (port-next-location port)])
(list src line col pos (and pos (- p pos)))))]))
(define readtable
(make-readtable #f #\{ 'dispatch-macro parse-id-type))
(define (*read inp)
(parameterize ([current-readtable readtable])
(read inp)))
(define (*read-syntax src port)
(parameterize ([current-readtable readtable])
(read-syntax src port)))
(provide (rename *read read) (rename *read-syntax read-syntax))
)

View File

@ -0,0 +1,392 @@
#lang scribble/doc
@begin[(require scribble/manual)
(require (for-label typed-scheme/lang/main))]
@begin[
(define (item* header . args) (apply item @bold[header]{: } args))
(define-syntax-rule (tmod forms ...) (schememod typed-scheme forms ...))
]
@title[#:tag "top"]{@bold{Typed Scheme}: Scheme with Static Types}
@(defmodulelang typed-scheme #:use-sources (typed-scheme/lang/main))
Typed Scheme is a Scheme-like language, with a type system that
supports common Scheme programming idioms. Explicit type declarations
are required --- that is, there is no type inference. The language
supports a number of features from previous work on type systems that
make it easier to type Scheme programs, as well as a novel idea dubbed
@italic{occurrence typing} for case discrimination.
Typed Scheme is also designed to integrate with the rest of your PLT
Scheme system. It is possible to convert a single module to Typed
Scheme, while leaving the rest of the program unchanged. The typed
module is protected from the untyped code base via
automatically-synthesized contracts.
Further information on Typed Scheme is available from
@link["http://www.ccs.neu.edu/home/samth/typed-scheme"]{the homepage}.
@section{Starting with Typed Scheme}
If you already know PLT Scheme, or even some other Scheme, it should be
easy to start using Typed Scheme.
@subsection{A First Function}
The following program defines the Fibonacci function in PLT Scheme:
@schememod[scheme
(define (fib n)
(cond [(= 0 n) 1]
[(= 1 n) 1]
[else (+ (fib (- n 1)) (fib (- n 2)))]))
]
This program defines the same program using Typed Scheme.
@schememod[typed-scheme
(: fib (Number -> Number))
(define (fib n)
(cond [(= 0 n) 1]
[(= 1 n) 1]
[else (+ (fib (- n 1)) (fib (- n 2)))]))
]
There are two differences between these programs:
@itemize{
@item*[@elem{The Language}]{@schememodname[scheme] has been replaced by @schememodname[typed-scheme].}
@item*[@elem{The Type Annotation}]{We have added a type annotation
for the @scheme[fib] function, using the @scheme[:] form.} }
In general, these are most of the changes that have to be made to a
PLT Scheme program to transform it into a Typed Scheme program.
@margin-note{Changes to uses of @scheme[require] may also be necessary
- these are described later.}
@subsection[#:tag "complex"]{Adding more complexity}
Other typed binding forms are also available. For example, we could have
rewritten our fibonacci program as follows:
@schememod[typed-scheme
(: fib (Number -> Number))
(define (fib n)
(let ([base? (or (= 0 n) (= 1 n))])
(if base? 1
(+ (fib (- n 1)) (fib (- n 2))))))
]
This program uses the @scheme[let] binding form, but no new type
annotations are required. Typed Scheme infers the type of
@scheme[base?].
We can also define mutually-recursive functions:
@schememod[typed-scheme
(: my-odd? (Number -> Boolean))
(define (my-odd? n)
(if (= 0 n) #f
(my-even? (- n 1))))
(: my-even? (Number -> Boolean))
(define (my-even? n)
(if (= 0 n) #t
(my-odd? (- n 1))))
(display (my-even? 12))
]
As expected, this program prints @schemeresult[#t].
@subsection{Defining New Datatypes}
If our program requires anything more than atomic data, we must define
new datatypes. In Typed Scheme, structures can be defined, similarly
to PLT Scheme structures. The following program defines a date
structure and a function that formats a date as a string, using PLT
Scheme's built-in @scheme[format] function.
@schememod[typed-scheme
(define-typed-struct Date ([day : Number] [month : String] [year : Number]))
(: format-date (Date -> String))
(define (format-date d)
(format "Today is day ~a of ~a in the year ~a"
(Date-day d) (Date-month d) (Date-year d)))
(display (format-date (make-Date 28 "November" 2006)))
]
Here we see the new built-in type @scheme[String] as well as a definition
of the new user-defined type @scheme[my-date]. To define
@scheme[my-date], we provide all the information usually found in a
@scheme[define-struct], but added type annotations to the fields using
the @scheme[define-typed-struct] form.
Then we can use the functions that this declaration creates, just as
we would have with @scheme[define-struct].
@subsection{Recursive Datatypes and Unions}
Many data structures involve multiple variants. In Typed Scheme, we
represent these using @italic{union types}, written @scheme[(U t1 t2 ...)].
@schememod[typed-scheme
(define-type-alias Tree (U leaf node))
(define-typed-struct leaf ([val : Number]))
(define-typed-struct node ([left : Tree] [right : Tree]))
(: tree-height (Tree -> Number))
(define (tree-height t)
(cond [(leaf? t) 1]
[else (max (tree-height (node-left t))
(tree-height (node-right t)))]))
(: tree-sum (Tree -> Number))
(define (tree-sum t)
(cond [(leaf? t) (leaf-val t)]
[else (+ (tree-sum (node-left t))
(tree-sum (node-right t)))]))
]
In this module, we have defined two new datatypes: @scheme[leaf] and
@scheme[node]. We've also defined the type alias @scheme[Tree] to be
@scheme[(U node leaf)], which represents a binary tree of numbers. In
essence, we are saying that the @scheme[tree-height] function accepts
a @scheme[Tree], which is either a @scheme[node] or a @scheme[leaf],
and produces a number.
In order to calculate interesting facts about trees, we have to take
them apart and get at their contents. But since accessors such as
@scheme[node-left] require a @scheme[node] as input, not a
@scheme[Tree], we have to determine which kind of input we
were passed.
For this purpose, we use the predicates that come with each defined
structure. For example, the @scheme[leaf?] predicate distinguishes
@scheme[leaf]s from all other Typed Scheme values. Therefore, in the
first branch of the @scheme[cond] clause in @scheme[tree-sum], we know
that @scheme[t] is a @scheme[leaf], and therefore we can get its value
with the @scheme[leaf-val] function.
In the else clauses of both functions, we know that @scheme[t] is not
a @scheme[leaf], and since the type of @scheme[t] was @scheme[Tree] by
process of elimination we can determine that @scheme[t] must be a
@scheme[node]. Therefore, we can use accessors such as
@scheme[node-left] and @scheme[node-right] with @scheme[t] as input.
@section{Polymorphism}
Virtually every Scheme program uses lists and sexpressions. Fortunately, Typed
Scheme can handle these as well. A simple list processing program can be
written like this:
@schememod[typed-scheme
(: sum-list ((Listof Number) -> Number))
(define (sum-list l)
(cond [(null? l) 0]
[else (+ (car l) (sum-list (cdr l)))]))
]
This looks similar to our earlier programs --- except for the type
of @scheme[l], which looks like a function application. In fact, it's
a use of the @italic{type constructor} @scheme[Listof], which takes
another type as its input, here @scheme[Number]. We can use
@scheme[Listof] to construct the type of any kind of list we might
want.
We can define our own type constructors as well. For example, here is
an analog of the @tt{Maybe} type constructor from Haskell:
@schememod[typed-scheme
(define-typed-struct Nothing ())
(define-typed-struct (a) Just ([v : a]))
(define-type-alias (Maybe a) (U Nothing (Just a)))
(: find (Number (Listof Number) -> (Maybe Number)))
(define (find v l)
(cond [(null? l) (make-Nothing)]
[(= v (car l)) (make-Just v)]
[else (find v (cdr l))]))
]
The first @scheme[define-typed-struct] defines @scheme[Nothing] to be
a structure with no contents.
The second definition
@schemeblock[
(define-typed-struct (a) Just ([v : a]))
]
creates a parameterized type, @scheme[Just], which is a structure with
one element, whose type is that of the type argument to
@scheme[Just]. Here the type parameters (only one, @scheme[a], in
this case) are written before the type name, and can be referred to in
the types of the fields.
The type alias definiton
@schemeblock[
(define-type-alias (Maybe a) (U Nothing (Just a)))
]
creates a parameterized alias --- @scheme[Maybe] is a potential
container for whatever type is supplied.
The @scheme[find] function takes a number @scheme[v] and list, and
produces @scheme[(make-Just v)] when the number is found in the list,
and @scheme[(make-Nothing)] otherwise. Therefore, it produces a
@scheme[(Maybe Number)], just as the annotation specified.
@section[#:tag "type-ref"]{Type Reference}
@subsubsub*section{Base Types}
These types represent primitive Scheme data.
@defidform[Number]{Any number}
@defidform[Boolean]{Either @scheme[#t] or @scheme[#f]}
@defidform[String]{A string}
@defidform[Keyword]{A PLT Scheme literal keyword}
@defidform[Symbol]{A symbol}
@defidform[Any]{Any value}
@subsubsub*section{Type Constructors}
The following constructors are parameteric in their type arguments.
@defform[(Listof t)]{Homogenous lists of @scheme[t]}
@defform[(Vectorof t)]{Homogenous vectors of @scheme[t]}
@defform[(Option t)]{Either @scheme[t] of @scheme[#f]}
@;{
@schemeblock[
(define: f : (Number -> Number) (lambda: ([x : Number]) 3))
]
}
@begin[
(require (for-syntax scheme/base))
(define-syntax (definfixform stx)
(syntax-case stx ()
[(_ dummy . rest) #'(begin (specform . rest))]))
#;
(define-syntax (definfixform stx)
(syntax-case stx ()
[(_ id spec desc ...)
#'(*defforms (quote-syntax id)
'()
'(spec)
(list (lambda (x) (schemeblock0 spec)))
'()
'()
(lambda () (list desc ...)))]))
]
@defform[(Pair s t)]{is the pair containing @scheme[s] as the @scheme[car]
and @scheme[t] as the @scheme[cdr]}
@defform[(-> dom ... rng)]{is the type of functions from the (possibly-empty)
sequence @scheme[dom ...] to the @scheme[rng] type.}
@defform[(U t ...)]{is the union of the types @scheme[t ...]}
@defform[(case-lambda fun-ty ...)]{is a function that behaves like all of
the @scheme[fun-ty]s. The @scheme[fun-ty]s must all be function
types constructed with @scheme[->].}
@defform/none[(t t1 t2 ...)]{is the instantiation of the parametric type
@scheme[t] at types @scheme[t1 t2 ...]}
@defform[(All (v ...) t)]{is a parameterization of type @scheme[t], with
type variables @scheme[v ...]}
@defform[(values t ...)]{is the type of a sequence of multiple values, with
types @scheme[t ...]. This can only appear as the return type of a
function.}
@defform/none[v]{where @scheme[v] is a number, boolean or string, is the singleton type containing
only that value}
@defform/none[i]{where @scheme[i] is an identifier can be a reference to a type
name or a type variable}
@defform[(Rec n t)]{is a recursive type where @scheme[n] is bound to the
recursive type in the body @scheme[t]}
Other types cannot be written by the programmer, but are used
internally and may appear in error messages.
@defform/none[(struct:n (t ...))]{is the type of structures named
@scheme[n] with field types @scheme[t]. There may be multiple such
types with the same printed representation.}
@defform/none[<n>]{is the printed representation of a reference to the
type variable @scheme[n]}
@section[#:tag "special-forms"]{Special Form Reference}
Typed Scheme provides a variety of special forms above and beyond
those in PLT Scheme. They are used for annotating variables with types,
creating new types, and annotating expressions.
@subsection{Binding Forms}
@scheme[_loop], @scheme[_f], @scheme[_a], and @scheme[_v] are names, @scheme[_t] is a type.
@scheme[_e] is an expression and @scheme[_body] is a block.
@defform*[[(define: (f [v : t] ...) : t body)
(define: v : t e)]]{}
@defform[
(pdefine: (a ...) (f [v : t] ...) : t body)]{}
@defform*[[
(let: ([v : t e] ...) body)
(let: loop : t0 ([v : t e] ...) body)]]{where @scheme[_t0] is the type of the
result of @scheme[_loop] (and thus the result of the entire expression).}
@defform[
(letrec: ([v : t e] ...) body)]{}
@defform[
(let*: ([v : t e] ...) body)]{}
@defform*[[
(lambda: ([v : t] ...) body)
(lambda: ([v : t] ... . [v : t]) body)]]{}
@defform*[[
(plambda: (a ...) ([v : t] ...) body)
(plambda: (a ...) ([v : t] ... . [v : t]) body)]]{}
@defform[
(case-lambda: [formals body] ...)]{where @scheme[_formals] is like
the second element of a @scheme[lambda:]}
@defform[
(pcase-lambda: (a ...) [formals body] ...)]{where @scheme[_formals] is like
the third element of a @scheme[plambda:]}
@subsection{Structure Definitions}
@defform*[[
(define-typed-struct name ([f : t] ...))
(define-typed-struct (name parent) ([f : t] ...))
(define-typed-struct (v ...) name ([f : t] ...))
(define-typed-struct (v ...) (name parent) ([f : t] ...))]]
@subsection{Type Aliases}
@defform*[[(define-type-alias name t)
(define-type-alias (name v ...) t)]]{}
@subsection{Type Annotation}
@defform[
(: v t)
]
@litchar{#{v : t}} This is legal only for binding occurences of @scheme[_v].
@litchar{#{e :: t}} This is legal only in expression contexts.
@subsection{Require}
Here, @scheme[_m] is a module spec, @scheme[_pred] is an identifier
naming a predicate, and @scheme[_r] is an optionally-renamed identifier.
@defform*[[
(require/typed r t m)
(require/typed m [r t] ...)
]]{}
@defform[(require/opaque-type t pred m)]{}
@defform[(require-typed-struct name ([f : t] ...) m)]{}

View File

@ -0,0 +1,150 @@
#lang scheme/base
(require "private/prims.ss"
"private/init-envs.ss"
"private/extra-procs.ss"
"private/internal-forms.ss"
"private/base-env.ss"
(for-syntax
scheme/base
"private/type-utils.ss"
"private/typechecker.ss"
"private/type-rep.ss"
"private/provide-handling.ss"
"private/type-environments.ss" "private/tc-utils.ss"
"private/type-env.ss" "private/type-name-env.ss"
"private/type-alias-env.ss"
"private/utils.ss"
"private/internal-forms.ss"
"private/init-envs.ss"
"private/type-effect-convenience.ss"
"private/effect-rep.ss"
"private/rep-utils.ss"
"private/type-contract.ss"
"private/nest.ss"
syntax/kerncase
mzlib/list
mzlib/plt-match))
(provide
;; provides syntax such as define: and define-typed-struct
(all-from-out "private/prims.ss")
;; provides some pointless procedures - should be removed
(all-from-out "private/extra-procs.ss"))
(provide-tnames)
(provide-extra-tnames)
(provide (rename-out [module-begin #%module-begin]
[with-handlers: with-handlers]
[top-interaction #%top-interaction]
[#%plain-lambda lambda]
[#%plain-app #%app]
[require require]))
(define-for-syntax catch-errors? #f)
(define-syntax (module-begin stx)
(define module-name (syntax-property stx 'enclosing-module-name))
;(printf "BEGIN: ~a~n" (syntax->datum stx))
(with-logging-to-file
(log-file-name (syntax-src stx) module-name)
(syntax-case stx ()
[(mb forms ...)
(nest
([begin (set-box! typed-context? #t)
(start-timing module-name)]
[with-handlers
([(lambda (e) (and catch-errors? (exn:fail? e) (not (exn:fail:syntax? e))))
(lambda (e) (tc-error "Internal error: ~a" e))])]
[parameterize (;; this parameter is for parsing types
[current-tvars initial-tvar-env]
;; this parameter is just for printing types
;; this is a parameter to avoid dependency issues
[current-type-names
(lambda ()
(append
(type-name-env-map (lambda (id ty)
(cons (syntax-e id) ty)))
(type-alias-env-map (lambda (id ty)
(cons (syntax-e id) ty)))))]
;; reinitialize seen type variables
[type-name-references null])]
[begin (do-time "Initialized Envs")]
;; local-expand the module
;; pmb = #%plain-module-begin
[with-syntax ([new-mod
(local-expand #`(#%plain-module-begin
forms ...)
'module-begin
null
#;stop-list)])]
[with-syntax ([(pmb body2 ...) #'new-mod])]
[begin (do-time "Local Expand Done")]
[with-syntax ([after-code (parameterize ([orig-module-stx stx]
[expanded-module-stx #'new-mod])
(type-check #'(body2 ...)))]
[check-syntax-help (syntax-property #'(void) 'disappeared-use (type-name-references))]
[(transformed-body ...) (remove-provides #'(body2 ...))])]
[with-syntax ([(transformed-body ...) (change-contract-fixups #'(transformed-body ...))])])
(do-time "Typechecked")
(printf "checked ~a~n" module-name)
#;(printf "created ~a types~n" (count!))
#;(printf "tried to create ~a types~n" (all-count!))
#;(printf "created ~a union types~n" (union-count!))
;; reconstruct the module with the extra code
#'(#%module-begin transformed-body ... after-code check-syntax-help))])))
(define-syntax (top-interaction stx)
(syntax-case stx ()
[(_ . (module . rest))
(eq? 'module (syntax-e #'module))
#'(module . rest)]
[(_ . form)
(nest
([begin (set-box! typed-context? #t)]
[parameterize (;; this paramter is for parsing types
[current-tvars initial-tvar-env]
;; this parameter is just for printing types
;; this is a parameter to avoid dependency issues
[current-type-names
(lambda ()
(append
(type-name-env-map (lambda (id ty)
(cons (syntax-e id) ty)))
(type-alias-env-map (lambda (id ty)
(cons (syntax-e id) ty)))))])]
;(do-time "Initialized Envs")
;; local-expand the module
[let ([body2 (local-expand #'(#%top-interaction . form) 'top-level null)])]
[parameterize ([orig-module-stx #'form]
[expanded-module-stx body2])]
;; typecheck the body, and produce syntax-time code that registers types
[let ([type (tc-toplevel-form body2)])])
(kernel-syntax-case body2 #f
[(head . _)
(or (free-identifier=? #'head #'define-values)
(free-identifier=? #'head #'define-syntaxes)
(free-identifier=? #'head #'require)
(free-identifier=? #'head #'provide)
(free-identifier=? #'head #'begin)
(type-equal? -Void (tc-result-t type)))
body2]
;; construct code to print the type
[_
(nest
([with-syntax ([b body2]
[ty-str (match type
[(tc-result: t)
(format "- : ~a\n" t)]
[x (int-err "bad type result: ~a" x)])])])
#`(let ([v b] [type 'ty-str])
(begin0
v
(printf type))))]))]))