www

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

mlish+adhoc.rkt (79066B)


      1 #lang s-exp "../typecheck.rkt"
      2 (require (only-in "../typecheck.rkt"
      3                   [define-typed-syntax def-typed-stx/no-provide]))
      4 (require (postfix-in - racket/fixnum)
      5          (postfix-in - racket/flonum))
      6 
      7 (extends
      8  "ext-stlc.rkt"
      9  #:except → define begin #%app λ #%datum
     10           + - * void = zero? sub1 add1 not let let* and
     11           #:rename [~→ ~ext-stlc:→])
     12 (require (rename-in (only-in "sysf.rkt" inst) [inst sysf:inst]))
     13 (provide inst)
     14 (require (only-in "ext-stlc.rkt" →?))
     15 (require (only-in "sysf.rkt" ~∀ ∀ ∀? Λ))
     16 (reuse × tup proj define-type-alias #:from "stlc+rec-iso.rkt")
     17 (require (only-in "stlc+rec-iso.rkt" ~× ×?)) ; using current-type=? from here
     18 (provide (rename-out [ext-stlc:and and] [ext-stlc:#%datum #%datum]))
     19 (reuse member length reverse list-ref cons nil isnil head tail list #:from "stlc+cons.rkt")
     20 (require (prefix-in stlc+cons: (only-in "stlc+cons.rkt" list cons nil)))
     21 (require (only-in "stlc+cons.rkt" ~List List? List))
     22 (reuse ref deref := Ref #:from "stlc+box.rkt")
     23 (require (rename-in (only-in "stlc+reco+var.rkt" tup proj ×)
     24            [tup rec] [proj get] [× ××]))
     25 (provide rec get ××)
     26 ;; for pattern matching
     27 (require (prefix-in stlc+cons: (only-in "stlc+cons.rkt" list)))
     28 (require (prefix-in stlc+tup: (only-in "stlc+tup.rkt" tup)))
     29 
     30 ;; ML-like language + ad-hoc polymorphism
     31 ;; - top level recursive functions
     32 ;; - user-definable algebraic datatypes
     33 ;; - pattern matching
     34 ;; - (local) type inference
     35 ;;
     36 ;; - type classes
     37 
     38 (provide → →/test => =>/test
     39          List Channel Thread Vector Sequence Hash String-Port Input-Port Regexp
     40          define-type define-typeclass define-instance
     41          match2)
     42 
     43 (define-type-constructor => #:arity > 0)
     44 
     45 ;; providing version of define-typed-syntax
     46 (define-syntax (define-typed-syntax stx)
     47   (syntax-parse stx
     48     [(_ name:id #:export-as out-name:id . rst)
     49      #'(begin-
     50          (provide- (rename-out [name out-name]))
     51          (def-typed-stx/no-provide name . rst))]
     52     [(_ name:id . rst)
     53      #'(define-typed-syntax name #:export-as name . rst)]))
     54 
     55 ;; type class helper fns
     56 (begin-for-syntax
     57   (define (mk-app-err-msg stx #:expected [expected-τs #'()]
     58                               #:given [given-τs #'()]
     59                               #:note [note ""]
     60                               #:name [name #f]
     61                               #:action [other #f])
     62     (syntax-parse stx
     63       #;[(app . rst)
     64          #:when (not (equal? '#%app (syntax->datum #'app)))
     65          (mk-app-err-msg (syntax/loc stx (#%app app . rst))
     66                          #:expected expected-τs
     67                          #:given given-τs
     68                          #:note note
     69                          #:name name)]
     70       [(app e_fn e_arg ...)
     71        (define fn-name
     72          (if name name
     73              (format "function ~a"
     74                      (syntax->datum (or (get-orig #'e_fn) #'e_fn)))))
     75        (define action (if other other "applying"))
     76        (string-append
     77         (format "~a (~a:~a):\nType error "
     78                 (syntax-source stx) (syntax-line stx) (syntax-column stx))
     79         action " "
     80         fn-name ". " note "\n"
     81         (format "  Expected: ~a argument(s) with type(s): " (stx-length expected-τs))
     82         (types->str expected-τs) "\n"
     83         "  Given:\n"
     84         (string-join
     85          (map (λ (e t) (format "    ~a : ~a" e t)) ; indent each line
     86               (syntax->datum #'(e_arg ...))
     87               (if (stx-length=? #'(e_arg ...) given-τs)
     88                   (stx-map type->str given-τs)
     89                   (stx-map (lambda (e) "?") #'(e_arg ...))))
     90          "\n")
     91         "\n")]))
     92   (define (type-hash-code tys) ; tys should be fully expanded
     93     (equal-hash-code (syntax->datum (if (syntax? tys) tys #`#,tys))))
     94   (define (mangle o tys)
     95     (format-id o "~a~a" o (type-hash-code tys)))
     96   ;; pattern expander for type class
     97   (define-syntax ~TC
     98     (pattern-expander
     99      (syntax-parser
    100        [(_ [generic-op ty-concrete-op] (~and ooo (~literal ...)))
    101         #'(_ (_ (_ generic-op) ty-concrete-op) ooo)]
    102        [(_ . ops+tys) 
    103         #:with expanded (generate-temporary)
    104         #'(~and expanded
    105             (~parse (_ (_ (_ gen-op) ty-op) (... ...)) 
    106                     #'expanded)
    107             (~parse ops+tys #'((gen-op ty-op) (... ...))))])))
    108   (define-syntax ~TC-base
    109     (pattern-expander
    110      (syntax-parser
    111       [(_ . pat)
    112        #:with expanded (generate-temporary)
    113        #'(~and expanded
    114               (~parse ((~TC . pat) . _) (flatten-TC #'expanded)))])))
    115   (define-syntax ~TCs
    116     (pattern-expander
    117      (syntax-parser
    118       ;; pat should be of shape ([op ty] ...)
    119       [(_ pat (~and ooo (~literal ...)))
    120        #:with expanded (generate-temporary)
    121        ;; (stx-map (compose remove-dups flatten-TC) #'expanded) 
    122        ;;  produces [List [List [List op+ty]]]
    123        ;; - inner [List op+ty] is from the def of a TC
    124        ;; - second List is from the flattened subclass TCs
    125        ;; - outer List is bc this pattern matces multiple TCs
    126        ;; This pattern expander collapses the inner two Lists
    127        #'(~and expanded
    128               (~parse (((~TC [op ty] (... ...)) (... ...)) ooo)
    129                       (stx-map (compose remove-dups flatten-TC) #'expanded))
    130               (~parse (pat ooo) #'(([op ty] (... ...) (... ...)) ooo)))])))
    131   (define (flatten-TC TC)
    132     (syntax-parse TC
    133       [(~=> sub-TC ... base-TC)
    134        (cons #'base-TC (stx-appendmap flatten-TC #'(sub-TC ...)))]))
    135   (define (remove-dups TCs)
    136     (syntax-parse TCs
    137       [() #'()]
    138       [(TC . rst)
    139        (cons #'TC (stx-filter (lambda (s) (not (typecheck? s #'TC))) (remove-dups #'rst)))])))
    140 ;; type inference constraint solving
    141 (begin-for-syntax 
    142   ;; matching possibly polymorphic types
    143   (define-syntax ~?∀
    144     (pattern-expander
    145      (lambda (stx)
    146        (syntax-case stx ()
    147          [(?∀ vars-pat body-pat)
    148           #'(~or (~∀ vars-pat body-pat)
    149                  (~and (~not (~∀ _ _))
    150                        (~parse vars-pat #'())
    151                        body-pat))]))))
    152 
    153   ;; type inference constraint solving
    154   (define (compute-constraint τ1-τ2)
    155     (syntax-parse τ1-τ2
    156       [(X:id τ) #'((X τ))]
    157       [((~Any tycons1 τ1 ...) (~Any tycons2 τ2 ...))
    158        #:when (typecheck? #'tycons1 #'tycons2)
    159        (compute-constraints #'((τ1 τ2) ...))]
    160       ; should only be monomorphic?
    161       [((~∀ () (~ext-stlc:→ τ1 ...)) (~∀ () (~ext-stlc:→ τ2 ...)))
    162        (compute-constraints #'((τ1 τ2) ...))]
    163       [_ #'()]))
    164   (define (compute-constraints τs) 
    165     (stx-appendmap compute-constraint τs))
    166 
    167   (define (solve-constraint x-τ)
    168     (syntax-parse x-τ
    169       [(X:id τ) #'((X τ))]
    170       [_ #'()]))
    171   (define (solve-constraints cs)
    172     (stx-appendmap compute-constraint cs))
    173   
    174   (define (lookup x substs)
    175     (syntax-parse substs
    176       [((y:id τ) . rst)
    177        #:when (free-identifier=? #'y x)
    178        #'τ]
    179       [(_ . rst) (lookup x #'rst)]
    180       [() #f]))
    181 
    182   ;; find-unsolved-Xs : (Stx-Listof Id) Constraints -> (Listof Id)
    183   ;; finds the free Xs that aren't constrained by cs
    184   (define (find-unsolved-Xs Xs cs)
    185     (for/list ([X (in-list (stx->list Xs))]
    186                #:when (not (lookup X cs)))
    187       X))
    188 
    189   ;; lookup-Xs/keep-unsolved : (Stx-Listof Id) Constraints -> (Listof Type-Stx)
    190   ;; looks up each X in the constraints, returning the X if it's unconstrained
    191   (define (lookup-Xs/keep-unsolved Xs cs)
    192     (for/list ([X (in-list (stx->list Xs))])
    193       (or (lookup X cs) X)))
    194 
    195   ;; solve for Xs by unifying quantified fn type with the concrete types of stx's args
    196   ;;   stx = the application stx = (#%app e_fn e_arg ...)
    197   ;;   tyXs = input and output types from fn type
    198   ;;          ie (typeof e_fn) = (-> . tyXs)
    199   ;; It infers the types of arguments from left-to-right,
    200   ;; and it short circuits if it's done early.
    201   ;; It returns list of 3 values if successful, else throws a type error
    202   ;;  - a list of the arguments that it expanded
    203   ;;  - a list of the the un-constrained type variables
    204   ;;  - the constraints for substituting the types
    205   (define (solve Xs tyXs stx)
    206     (syntax-parse tyXs
    207       [(τ_inX ... τ_outX)
    208        ;; generate initial constraints with expected type and τ_outX
    209        #:with expected-ty (get-expected-type stx)
    210        (define initial-cs
    211          (if (syntax-e #'expected-ty)
    212              (compute-constraint (list #'τ_outX ((current-type-eval) #'expected-ty)))
    213              #'()))
    214        (syntax-parse stx
    215          [(_ e_fn . args)
    216           (define-values (as- cs)
    217               (for/fold ([as- null] [cs initial-cs])
    218                         ([a (in-list (syntax->list #'args))]
    219                          [tyXin (in-list (syntax->list #'(τ_inX ...)))]
    220                          #:break (empty? (find-unsolved-Xs Xs cs)))
    221                 (define/with-syntax [a- ty_a] (infer+erase a))
    222                 (values 
    223                  (cons #'a- as-)
    224                  (stx-append cs (compute-constraint (list tyXin #'ty_a))))))
    225 
    226          (list (reverse as-) (find-unsolved-Xs Xs cs) cs)])]))
    227 
    228   (define (raise-app-poly-infer-error stx expected-tys given-tys e_fn)
    229     (type-error #:src stx
    230      #:msg (mk-app-err-msg stx #:expected expected-tys #:given given-tys
    231             #:note (format "Could not infer instantiation of polymorphic function ~a."
    232                            (syntax->datum (get-orig e_fn))))))
    233 
    234   ;; instantiate polymorphic types
    235   ;; inst-type : (Listof Type) (Listof Id) Type -> Type
    236   ;; Instantiates ty with the tys-solved substituted for the Xs, where the ith
    237   ;; identifier in Xs is associated with the ith type in tys-solved
    238   (define (inst-type tys-solved Xs ty)
    239     (substs tys-solved Xs ty))
    240   
    241   ;; inst-type/cs : (Stx-Listof Id) Constraints Type-Stx -> Type-Stx
    242   ;; Instantiates ty, substituting each identifier in Xs with its mapping in cs.
    243   (define (inst-type/cs Xs cs ty)
    244     (define tys-solved (lookup-Xs/keep-unsolved Xs cs))
    245     (inst-type tys-solved Xs ty))
    246   ;; inst-types/cs : (Stx-Listof Id) Constraints (Stx-Listof Type-Stx) -> (Listof Type-Stx)
    247   ;; the plural version of inst-type/cs
    248   (define (inst-types/cs Xs cs tys)
    249     (stx-map (lambda (t) (inst-type/cs Xs cs t)) tys))
    250 
    251   ;; compute unbound tyvars in one unexpanded type ty
    252   (define (compute-tyvar1 ty)
    253     (syntax-parse ty
    254       [X:id #'(X)]
    255       [() #'()]
    256       [(C t ...) (stx-appendmap compute-tyvar1 #'(t ...))]))
    257   ;; computes unbound ids in (unexpanded) tys, to be used as tyvars
    258   (define (compute-tyvars tys)
    259     (define Xs (stx-appendmap compute-tyvar1 tys))
    260     (filter 
    261      (lambda (X) 
    262        (with-handlers
    263         ([exn:fail:syntax:unbound? (lambda (e) #t)]
    264          [exn:fail:type:infer? (lambda (e) #t)])
    265         (let ([X+ ((current-type-eval) X)])
    266           (not (or (tyvar? X+) (type? X+))))))
    267      (stx-remove-dups Xs))))
    268 
    269 ;; define --------------------------------------------------
    270 ;; for function defs, define infers type variables
    271 ;; - since the order of the inferred type variables depends on expansion order,
    272 ;;   which is not known to programmers, to make the result slightly more
    273 ;;   intuitive, we arbitrarily sort the inferred tyvars lexicographically
    274 (define-typed-syntax define/tc #:export-as define
    275   [(_ x:id e)
    276    #:with (e- τ) (infer+erase #'e)
    277    #:with y (generate-temporary)
    278    #'(begin-
    279        (define-syntax- x (make-rename-transformer (⊢ y : τ)))
    280        (define- y e-))]
    281   ; explicit "forall"
    282   [(_ Ys (f:id [x:id (~datum :) τ] ... (~or (~datum ->) (~datum →)) τ_out) 
    283       e_body ... e)
    284    #:when (brace? #'Ys)
    285    ;; TODO; remove this code duplication
    286    #:with g (add-orig (generate-temporary #'f) #'f)
    287    #:with e_ann (syntax/loc #'e (add-expected e τ_out))
    288    #:with (τ+orig ...) (stx-map (λ (t) (add-orig t t)) #'(τ ... τ_out))
    289    ;; TODO: check that specified return type is correct
    290    ;; - currently cannot do it here; to do the check here, need all types of
    291    ;;  top-lvl fns, since they can call each other
    292    #:with (~and ty_fn_expected (~∀ _ (~ext-stlc:→ _ ... out_expected))) 
    293           ((current-type-eval) #'(∀ Ys (ext-stlc:→ τ+orig ...)))
    294    #`(begin-
    295       (define-syntax- f (make-rename-transformer (⊢ g : ty_fn_expected)))
    296       (define- g
    297         (Λ Ys (ext-stlc:λ ([x : τ] ...) (ext-stlc:begin e_body ... e_ann)))))]
    298   ;; alternate type sig syntax, after parameter names
    299   [(_ (f:id x:id ...) (~datum :) ty ... (~or (~datum ->) (~datum →)) ty_out . b)
    300    (syntax/loc stx (define/tc (f [x : ty] ... -> ty_out) . b))]
    301   [(_ (f:id [x:id (~datum :) τ] ... ; no TC
    302             (~or (~datum ->) (~datum →)) τ_out)
    303       e_body ... e)
    304    #:with (~and Ys (Y ...)) (compute-tyvars #'(τ ... τ_out))
    305    #:with g (add-orig (generate-temporary #'f) #'f)
    306    #:with e_ann (syntax/loc #'e (add-expected e τ_out)) ; must be macro bc t_out may have unbound tvs
    307    #:with (τ+orig ...) (stx-map (λ (t) (add-orig t t)) #'(τ ... τ_out))
    308    ;; TODO: check that specified return type is correct
    309    ;; - currently cannot do it here; to do the check here, need all types of
    310    ;;  top-lvl fns, since they can call each other
    311    #:with ty_fn_expected
    312           (set-stx-prop/preserved 
    313            ((current-type-eval) #'(∀ Ys (ext-stlc:→ τ+orig ...)))
    314            'orig
    315            (list #'(→ τ+orig ...)))
    316    #`(begin-
    317       (define-syntax- f (make-rename-transformer (⊢ g : ty_fn_expected)))
    318       (define- g
    319         (Λ Ys (ext-stlc:λ ([x : τ] ...) (ext-stlc:begin e_body ... e_ann)))))]
    320   [(_ (f:id [x:id (~datum :) τ] ... 
    321             (~seq #:where TC ...)
    322             (~or (~datum ->) (~datum →)) τ_out)
    323       e_body ... e)
    324    #:with (~and Ys (Y ...)) (compute-tyvars #'(τ ... τ_out))
    325    #:with g (add-orig (generate-temporary #'f) #'f)
    326    #:with e_ann (syntax/loc #'e (add-expected e τ_out)) ; must be macro bc t_out may have unbound tvs
    327    #:with (τ+orig ...) (stx-map (λ (t) (add-orig t t)) #'(τ ... τ_out))
    328    ;; TODO: check that specified return type is correct
    329    ;; - currently cannot do it here; to do the check here, need all types of
    330    ;;  top-lvl fns, since they can call each other
    331    #:with (~and ty_fn_expected (~∀ _ (~=> _ ... (~ext-stlc:→ _ ... out_expected))))
    332           (syntax-property 
    333               ((current-type-eval) #'(∀ Ys (=> TC ... (ext-stlc:→ τ+orig ...))))
    334             'orig
    335             (list #'(→ τ+orig ...)))
    336    #`(begin-
    337       (define-syntax- f (make-rename-transformer (⊢ g : ty_fn_expected)))
    338        #,(quasisyntax/loc stx
    339           (define- g
    340           ;(Λ Ys (ext-stlc:λ ([x : τ] ...) (ext-stlc:begin e_body ... e_ann)))))])
    341            (liftedλ {Y ...} ([x : τ] ... #:where TC ...) 
    342             #,(syntax/loc #'e_ann (ext-stlc:begin e_body ... e_ann))))))])
    343 
    344 ;; define-type -----------------------------------------------
    345 ;; TODO: should validate τ as part of define-type definition (before it's used)
    346 ;; - not completely possible, since some constructors may not be defined yet,
    347 ;;   ie, mutually recursive datatypes
    348 ;; for now, validate types but punt if encountering unbound ids
    349 (define-syntax (define-type stx)
    350   (syntax-parse stx
    351     [(_ Name:id . rst)
    352      #:with NewName (generate-temporary #'Name)
    353      #:with Name2 (add-orig #'(NewName) #'Name)
    354      #`(begin-
    355          (define-type Name2 . #,(subst #'Name2 #'Name #'rst))
    356          (stlc+rec-iso:define-type-alias Name Name2))]
    357     [(_ (Name:id X:id ...)
    358         ;; constructors must have the form (Cons τ ...)
    359         ;; but the first ~or clause accepts 0-arg constructors as ids;
    360         ;; the ~and is a workaround to bind the duplicate Cons ids (see Ryan's email)
    361         (~and (~or (~and IdCons:id 
    362                         (~parse (Cons [fld (~datum :) τ] ...) #'(IdCons)))
    363                    (Cons [fld (~datum :) τ] ...)
    364                    (~and (Cons τ ...)
    365                          (~parse (fld ...) (generate-temporaries #'(τ ...)))))) ...)
    366      ;; validate tys
    367      #:with (ty_flat ...) (stx-flatten #'((τ ...) ...))
    368      #:with (_ _ (_ _ (_ _ (_ _ ty+ ...))))
    369             (with-handlers 
    370               ([exn:fail:syntax:unbound?
    371                 (λ (e) 
    372                   (define X (stx-car (exn:fail:syntax-exprs e)))
    373                   #`(lambda () (let-syntax () (let-syntax () (#%app void unbound)))))])
    374               (expand/df 
    375                 #`(lambda (X ...)
    376                     (let-syntax 
    377                       ([Name 
    378                         (syntax-parser 
    379                          [(_ X ...) (mk-type #'void)]
    380                          [stx 
    381                           (type-error 
    382                            #:src #'stx
    383                            #:msg 
    384                            (format "Improper use of constructor ~a; expected ~a args, got ~a"
    385                                    (syntax->datum #'Name) (stx-length #'(X ...))
    386                                    (stx-length (stx-cdr #'stx))))])]
    387                        [X (make-rename-transformer (mk-type #'X))] ...)
    388                       (void ty_flat ...)))))
    389      #:when (or (equal? '(unbound) (syntax->datum #'(ty+ ...)))
    390                 (stx-map 
    391                   (lambda (t+ t) (unless (type? t+)
    392                               (type-error #:src t
    393                                           #:msg "~a is not a valid type" t)))
    394                   #'(ty+ ...) #'(ty_flat ...)))
    395      #:with NameExpander (format-id #'Name "~~~a" #'Name)
    396      #:with NameExtraInfo (format-id #'Name "~a-extra-info" #'Name)
    397      #:with (StructName ...) (generate-temporaries #'(Cons ...))
    398      #:with ((e_arg ...) ...) (stx-map generate-temporaries #'((τ ...) ...))
    399      #:with ((e_arg- ...) ...) (stx-map generate-temporaries #'((τ ...) ...))
    400      #:with ((τ_arg ...) ...) (stx-map generate-temporaries #'((τ ...) ...))
    401      #:with ((exposed-acc ...) ...)
    402             (stx-map 
    403               (λ (C fs) (stx-map (λ (f) (format-id C "~a-~a" C f)) fs))
    404               #'(Cons ...) #'((fld ...) ...))
    405      #:with ((acc ...) ...) (stx-map (λ (S fs) (stx-map (λ (f) (format-id S "~a-~a" S f)) fs))
    406                                      #'(StructName ...) #'((fld ...) ...))
    407      #:with (Cons? ...) (stx-map mk-? #'(StructName ...))
    408      #:with (exposed-Cons? ...) (stx-map mk-? #'(Cons ...))
    409      #`(begin-
    410          (define-syntax- (NameExtraInfo stx)
    411            (syntax-parse stx
    412              [(_ X ...) #'(('Cons 'StructName Cons? [acc τ] ...) ...)]))
    413          (define-type-constructor Name
    414            #:arity = #,(stx-length #'(X ...))
    415            #:extra-info 'NameExtraInfo)
    416          (struct- StructName (fld ...) #:reflection-name 'Cons #:transparent) ...
    417          (define-syntax- (exposed-acc stx) ; accessor for records
    418            (syntax-parse stx
    419             [_:id (⊢ acc (∀ (X ...) (ext-stlc:→ (Name X ...) τ)))]
    420             [(o . rst) ; handle if used in fn position
    421              #:with app (datum->syntax #'o '#%app)
    422              #`(app 
    423                 #,(assign-type #'acc #'(∀ (X ...) (ext-stlc:→ (Name X ...) τ))) 
    424                 . rst)])) ... ...
    425          (define-syntax- (exposed-Cons? stx) ; predicates for each variant
    426            (syntax-parse stx
    427             [_:id (⊢ Cons? (∀ (X ...) (ext-stlc:→ (Name X ...) Bool)))]
    428             [(o . rst) ; handle if used in fn position
    429              #:with app (datum->syntax #'o '#%app)
    430              #`(app 
    431                 #,(assign-type #'Cons? #'(∀ (X ...) (ext-stlc:→ (Name X ...) Bool))) 
    432                 . rst)])) ...
    433          (define-syntax- (Cons stx)
    434            (syntax-parse stx
    435              ; no args and not polymorphic
    436              [C:id #:when (and (stx-null? #'(X ...)) (stx-null? #'(τ ...))) #'(C)]
    437              ; no args but polymorphic, check inferred type
    438              [C:id
    439               #:when (stx-null? #'(τ ...))
    440               #:with τ-expected (syntax-property #'C 'expected-type)
    441               #:fail-unless (syntax-e #'τ-expected)
    442                             (raise
    443                               (exn:fail:type:infer
    444                                 (string-append
    445                                   (format "TYPE-ERROR: ~a (~a:~a): "
    446                                           (syntax-source stx) (syntax-line stx) (syntax-column stx))
    447                                   (format "cannot infer type of ~a; add annotations" 
    448                                           (syntax->datum #'C)))
    449                                 (current-continuation-marks)))
    450               #:with (NameExpander τ-expected-arg (... ...)) ((current-type-eval) #'τ-expected)
    451               #'(C {τ-expected-arg (... ...)})]
    452              [_:id (⊢ StructName (∀ (X ...) (ext-stlc:→ τ ... (Name X ...))))] ; HO fn
    453              [(C τs e_arg ...)
    454               #:when (brace? #'τs) ; commit to this clause
    455               #:with {~! τ_X:type (... ...)} #'τs
    456               #:with (τ_in:type (... ...)) ; instantiated types
    457                      (stx-map
    458                       (λ (t) (substs #'(τ_X.norm (... ...)) #'(X ...) t))
    459                       #'(τ ...))
    460               #:with ([e_arg- τ_arg] ...)
    461                      (stx-map
    462                       (λ (e τ_e)
    463                         (infer+erase (set-stx-prop/preserved e 'expected-type τ_e)))
    464                       #'(e_arg ...) #'(τ_in.norm (... ...)))
    465               #:fail-unless (typechecks? #'(τ_arg ...) #'(τ_in.norm (... ...)))
    466                            (mk-app-err-msg (syntax/loc stx (#%app C e_arg ...))
    467                             #:expected #'(τ_in.norm (... ...)) #:given #'(τ_arg ...)
    468                             #:name (format "constructor ~a" 'Cons))
    469               (⊢ (StructName e_arg- ...) : (Name τ_X (... ...)))]
    470              [(C . args) ; no type annotations, must infer instantiation
    471               #:with StructName/ty 
    472                      (set-stx-prop/preserved
    473                       (⊢ StructName : (∀ (X ...) (ext-stlc:→ τ ... (Name X ...))))
    474                       'orig
    475                       (list #'C))
    476               ; stx/loc transfers expected-type
    477               (syntax/loc stx (mlish:#%app StructName/ty . args))]))
    478          ...)]))
    479 
    480 ;; match --------------------------------------------------
    481 (begin-for-syntax
    482   (define (get-ctx pat ty)
    483     (unify-pat+ty (list pat ty)))
    484   (define (unify-pat+ty pat+ty)
    485     (syntax-parse pat+ty
    486      [(pat ty) #:when (brace? #'pat) ; handle root pattern specially (to avoid some parens)
    487       (syntax-parse #'pat
    488         [{(~datum _)} #'()]
    489         [{(~literal stlc+cons:nil)}  #'()]
    490         [{A:id} ; disambiguate 0-arity constructors (that don't need parens)
    491          #:when (get-extra-info #'ty)
    492          #'()]
    493         ;; comma tup syntax always has parens
    494         [{(~and ps (p1 (unq p) ...))}
    495          #:when (not (stx-null? #'(p ...)))
    496          #:when (andmap (lambda (u) (equal? u 'unquote)) (syntax->datum #'(unq ...)))
    497          (unify-pat+ty #'(ps ty))]
    498         [{p ...} 
    499          (unify-pat+ty #'((p ...) ty))])] ; pair
    500       [((~datum _) ty) #'()]
    501       [((~or (~literal stlc+cons:nil)) ty) #'()]
    502       [(A:id ty) ; disambiguate 0-arity constructors (that don't need parens)
    503        #:with (_ (_ (_ C) . _) ...) (get-extra-info #'ty)
    504        #:when (member (syntax->datum #'A) (syntax->datum #'(C ...)))
    505        #'()]
    506       [(x:id ty)  #'((x ty))]
    507       [((p1 (unq p) ...) ty) ; comma tup stx
    508        #:when (not (stx-null? #'(p ...)))
    509        #:when (andmap (lambda (u) (equal? u 'unquote)) (syntax->datum #'(unq ...)))
    510        #:with (~× t ...) #'ty
    511        #:with (pp ...) #'(p1 p ...)
    512        (unifys #'([pp t] ...))]
    513       [(((~literal stlc+tup:tup) p ...) ty) ; tup
    514        #:with (~× t ...) #'ty
    515        (unifys #'([p t] ...))]
    516       [(((~literal stlc+cons:list) p ...) ty) ; known length list
    517        #:with (~List t) #'ty
    518        (unifys #'([p t] ...))]
    519      [(((~seq p (~datum ::)) ... rst) ty) ; nicer cons stx
    520       #:with (~List t) #'ty
    521        (unifys #'([p t] ... [rst ty]))]
    522       [(((~literal stlc+cons:cons) p ps) ty) ; arb length list
    523        #:with (~List t) #'ty
    524        (unifys #'([p t] [ps ty]))]
    525       [((Name p ...) ty)
    526        #:with (_ (_ Cons) _ _ [_ _ τ] ...)
    527               (stx-findf
    528                 (syntax-parser
    529                  [(_ 'C . rst) 
    530                   (equal? (syntax->datum #'Name) (syntax->datum #'C))])
    531                 (stx-cdr (get-extra-info #'ty)))
    532        (unifys #'([p τ] ...))]
    533       [p+t #:fail-when #t (format "could not unify ~a" (syntax->datum #'p+t))
    534        #'()]))
    535   (define (unifys p+tys) (stx-appendmap unify-pat+ty p+tys))
    536   
    537   (define (compile-pat p ty)
    538     (syntax-parse p
    539      [pat #:when (brace? #'pat) ; handle root pattern specially (to avoid some parens)
    540       (syntax-parse #'pat
    541         [{(~datum _)} #'_]
    542         [{(~literal stlc+cons:nil)}  (syntax/loc p (list))]
    543         [{A:id} ; disambiguate 0-arity constructors (that don't need parens)
    544          #:when (get-extra-info ty)
    545          (compile-pat #'(A) ty)]
    546         ;; comma tup stx always has parens
    547         [{(~and ps (p1 (unq p) ...))}
    548          #:when (not (stx-null? #'(p ...)))
    549          #:when (andmap (lambda (u) (equal? u 'unquote)) (syntax->datum #'(unq ...)))
    550          (compile-pat #'ps ty)]
    551         [{pat ...} (compile-pat (syntax/loc p (pat ...)) ty)])]
    552      [(~datum _) #'_]
    553      [(~literal stlc+cons:nil) ; nil
    554       #'(list)]
    555      [A:id ; disambiguate 0-arity constructors (that don't need parens)
    556       #:with (_ (_ (_ C) . _) ...) (get-extra-info ty)
    557       #:when (member (syntax->datum #'A) (syntax->datum #'(C ...)))
    558       (compile-pat #'(A) ty)]
    559      [x:id p]
    560      [(p1 (unq p) ...) ; comma tup stx
    561       #:when (not (stx-null? #'(p ...)))
    562       #:when (andmap (lambda (u) (equal? u 'unquote)) (syntax->datum #'(unq ...)))
    563       #:with (~× t ...) ty
    564       #:with (p- ...) (stx-map (lambda (p t) (compile-pat p t)) #'(p1 p ...) #'(t ...))
    565       #'(list p- ...)]
    566      [((~literal stlc+tup:tup) . pats)
    567       #:with (~× . tys) ty
    568       #:with (p- ...) (stx-map (lambda (p t) (compile-pat p t)) #'pats #'tys)
    569       (syntax/loc p (list p- ...))]
    570      [((~literal stlc+cons:list) . ps)
    571       #:with (~List t) ty
    572       #:with (p- ...) (stx-map (lambda (p) (compile-pat p #'t)) #'ps)
    573       (syntax/loc p (list p- ...))]
    574      [((~seq pat (~datum ::)) ... last) ; nicer cons stx
    575       #:with (~List t) ty
    576       #:with (p- ...) (stx-map (lambda (pp) (compile-pat pp #'t)) #'(pat ...))
    577       #:with last- (compile-pat #'last ty)
    578       (syntax/loc p (list-rest p- ... last-))]
    579      [((~literal stlc+cons:cons) p ps)
    580       #:with (~List t) ty
    581       #:with p- (compile-pat #'p #'t)
    582       #:with ps- (compile-pat #'ps ty)
    583       #'(cons p- ps-)]
    584      [(Name . pats)
    585       #:with (_ (_ Cons) (_ StructName) _ [_ _ τ] ...)
    586              (stx-findf
    587                (syntax-parser
    588                 [(_ 'C . rst) 
    589                  (equal? (syntax->datum #'Name) (syntax->datum #'C))])
    590                (stx-cdr (get-extra-info ty)))
    591       #:with (p- ...) (stx-map compile-pat #'pats #'(τ ...))
    592       (syntax/loc p (StructName p- ...))]))
    593 
    594   ;; pats = compiled pats = racket pats
    595   (define (check-exhaust pats ty)
    596     (define (else-pat? p)
    597       (syntax-parse p [(~literal _) #t] [_ #f]))
    598     (define (nil-pat? p)
    599       (syntax-parse p
    600         [((~literal list)) #t]
    601         [_ #f]))
    602     (define (non-nil-pat? p)
    603       (syntax-parse p
    604         [((~literal list-rest) . rst) #t]
    605         [((~literal cons) . rst) #t]
    606         [_ #f]))
    607     (define (tup-pat? p)
    608       (syntax-parse p
    609         [((~literal list) . _) #t] [_ #f]))
    610     (cond
    611      [(or (stx-ormap else-pat? pats) (stx-ormap identifier? pats)) #t]
    612      [(List? ty) ; lists
    613       (unless (stx-ormap nil-pat? pats)
    614         (error 'match2 (let ([last (car (stx-rev pats))])
    615                          (format "(~a:~a) missing nil clause for list expression"
    616                                  (syntax-line last) (syntax-column last)))))
    617       (unless (stx-ormap non-nil-pat? pats)
    618         (error 'match2 (let ([last (car (stx-rev pats))])
    619                          (format "(~a:~a) missing clause for non-empty, arbitrary length list"
    620                                  (syntax-line last) (syntax-column last)))))
    621       #t]
    622      [(×? ty) ; tuples
    623       (unless (stx-ormap tup-pat? pats)
    624         (error 'match2 (let ([last (car (stx-rev pats))])
    625                          (format "(~a:~a) missing pattern for tuple expression"
    626                                  (syntax-line last) (syntax-column last)))))
    627       (syntax-parse pats
    628         [((_ p ...) ...)
    629          (syntax-parse ty
    630            [(~× t ...)
    631             (apply stx-andmap 
    632                    (lambda (t . ps) (check-exhaust ps t)) 
    633                    #'(t ...) 
    634                    (syntax->list #'((p ...) ...)))])])]
    635      [else ; algebraic datatypes
    636       (syntax-parse (get-extra-info ty)
    637         [(_ (_ (_ C) (_ Cstruct) . rst) ...)
    638          (syntax-parse pats
    639            [((Cpat _ ...) ...)
    640             (define Cs (syntax->datum #'(C ...)))
    641             (define Cstructs (syntax->datum #'(Cstruct ...)))
    642             (define Cpats (syntax->datum #'(Cpat ...)))
    643             (unless (set=? Cstructs Cpats)
    644               (error 'match2
    645                 (let ([last (car (stx-rev pats))])
    646                   (format "(~a:~a) clauses not exhaustive; missing: ~a"
    647                           (syntax-line last) (syntax-column last)
    648                           (string-join      
    649                             (for/list ([C Cs][Cstr Cstructs] #:unless (member Cstr Cpats))
    650                               (symbol->string C))
    651                             ", ")))))
    652             #t])]
    653         [_ #t])]))
    654 
    655   ;; TODO: do get-ctx and compile-pat in one pass
    656   (define (compile-pats pats ty)
    657     (stx-map (lambda (p) (list (get-ctx p ty) (compile-pat p ty))) pats))
    658   )
    659 
    660 (define-syntax (match2 stx)
    661  (syntax-parse stx #:datum-literals (with)
    662    [(_ e with . clauses)
    663     #:fail-when (null? (syntax->list #'clauses)) "no clauses"
    664     #:with [e- τ_e] (infer+erase #'e)
    665     (syntax-parse #'clauses #:datum-literals (->)
    666      [([(~seq p ...) -> e_body] ...)
    667       #:with (pat ...) (stx-map ; use brace to indicate root pattern
    668                          (lambda (ps) (syntax-parse ps [(pp ...) (syntax/loc stx {pp ...})]))
    669                          #'((p ...) ...)) 
    670       #:with ([(~and ctx ([x ty] ...)) pat-] ...) (compile-pats #'(pat ...) #'τ_e)
    671       #:with ty-expected (get-expected-type stx)
    672       #:with ([(x- ...) e_body- ty_body] ...) 
    673              (stx-map 
    674                infer/ctx+erase 
    675                #'(ctx ...) #'((add-expected e_body ty-expected) ...))
    676       #:when (check-exhaust #'(pat- ...) #'τ_e)
    677       #:with τ_out (stx-foldr (current-join) (stx-car #'(ty_body ...)) (stx-cdr #'(ty_body ...)))
    678       (⊢ (match- e- [pat- (let- ([x- x] ...) e_body-)] ...) : τ_out)
    679       ])]))
    680 
    681 (define-typed-syntax match #:datum-literals (with)
    682    [(_ e with . clauses)
    683     #:fail-when (null? (syntax->list #'clauses)) "no clauses"
    684     #:with [e- τ_e] (infer+erase #'e)
    685     #:with t_expect (syntax-property stx 'expected-type) ; propagate inferred type
    686     (cond
    687      [(×? #'τ_e) ;; e is tuple
    688       (syntax-parse #'clauses #:datum-literals (->)
    689        [([x ... -> e_body])
    690         #:with (~× ty ...) #'τ_e
    691         #:fail-unless (stx-length=? #'(ty ...) #'(x ...))
    692                       "match clause pattern not compatible with given tuple"
    693         #:with [(x- ...) e_body- ty_body] (infer/ctx+erase #'([x ty] ...) 
    694                                             #'(add-expected e_body t_expect))
    695         #:with (acc ...) (for/list ([(a i) (in-indexed (syntax->list #'(x ...)))])
    696                            #`(lambda (s) (list-ref s #,(datum->syntax #'here i))))
    697         #:with z (generate-temporary)
    698         (⊢ (let- ([z e-])
    699              (let- ([x- (acc z)] ...) e_body-))
    700            : ty_body)])]
    701      [(List? #'τ_e) ;; e is List
    702       (syntax-parse #'clauses #:datum-literals (-> ::)
    703        [([(~or (~and (~and xs [x ...]) (~parse rst (generate-temporary)))
    704                (~and (~seq (~seq x ::) ... rst:id) (~parse xs #'())))
    705           -> e_body] ...+)
    706         #:fail-unless (stx-ormap 
    707                         (lambda (xx) (and (brack? xx) (zero? (stx-length xx)))) 
    708                         #'(xs ...))
    709                       "match: missing empty list case"
    710         #:fail-when (and (stx-andmap brack? #'(xs ...))
    711                          (= 1 (stx-length #'(xs ...))))
    712                     "match: missing non-empty list case"
    713         #:with (~List ty) #'τ_e
    714         #:with ([(x- ... rst-) e_body- ty_body] ...)
    715                (stx-map (lambda (ctx e) (infer/ctx+erase ctx e)) 
    716                  #'(([x ty] ... [rst (List ty)]) ...) #'((add-expected e_body t_expect) ...))
    717         #:with τ_out (stx-foldr (current-join) (stx-car #'(ty_body ...)) (stx-cdr #'(ty_body ...)))
    718         #:with (len ...) (stx-map (lambda (p) #`#,(stx-length p)) #'((x ...) ...))
    719         #:with (lenop ...) (stx-map (lambda (p) (if (brack? p) #'=- #'>=-)) #'(xs ...))
    720         #:with (pred? ...) (stx-map
    721                             (lambda (l lo) #`(λ- (lst) (#,lo (length- lst) #,l)))
    722                             #'(len ...) #'(lenop ...))
    723         #:with ((acc1 ...) ...) (stx-map 
    724                                     (lambda (xs)
    725                                       (for/list ([(x i) (in-indexed (syntax->list xs))])
    726                                         #`(lambda (lst) (list-ref lst #,(datum->syntax #'here i)))))
    727                                   #'((x ...) ...))
    728         #:with (acc2 ...) (stx-map (lambda (l) #`(lambda (lst) (list-tail lst #,l))) #'(len ...))
    729         (⊢ (let- ([z e-])
    730              (cond- 
    731               [(pred? z)
    732                (let- ([x- (acc1 z)] ... [rst- (acc2 z)]) e_body-)] ...))
    733            : τ_out)])]
    734      [else  ;; e is variant
    735       (syntax-parse #'clauses #:datum-literals (->)
    736        [([Clause:id x:id ... 
    737              (~optional (~seq #:when e_guard) #:defaults ([e_guard #'(ext-stlc:#%datum . #t)]))
    738              -> e_c_un] ...+) ; un = unannotated with expected ty
    739         ;; length #'clauses may be > length #'info, due to guards
    740         #:with info-body (get-extra-info #'τ_e)
    741         #:with (_ (_ (_ ConsAll) . _) ...) #'info-body
    742         #:fail-unless (set=? (syntax->datum #'(Clause ...))
    743                              (syntax->datum #'(ConsAll ...)))
    744                       (type-error #:src stx
    745                        #:msg (string-append
    746                               "match: clauses not exhaustive; missing: "
    747                               (string-join      
    748                                 (map symbol->string
    749                                      (set-subtract 
    750                                        (syntax->datum #'(ConsAll ...))
    751                                        (syntax->datum #'(Clause ...))))
    752                                 ", ")))
    753         #:with ((_ _ _ Cons? [_ acc τ] ...) ...)
    754                (map ; ok to compare symbols since clause names can't be rebound
    755                 (lambda (Cl) 
    756                   (stx-findf
    757                       (syntax-parser
    758                         [(_ 'C . rst) (equal? Cl (syntax->datum #'C))])
    759                     (stx-cdr #'info-body))) ; drop leading #%app
    760                 (syntax->datum #'(Clause ...)))
    761         ;; this commented block experiments with expanding to unsafe ops
    762         ;; #:with ((acc ...) ...) (stx-map 
    763         ;;                         (lambda (accs)
    764         ;;                          (for/list ([(a i) (in-indexed (syntax->list accs))])
    765         ;;                            #`(lambda (s) (unsafe-struct*-ref s #,(datum->syntax #'here i)))))
    766         ;;                         #'((acc-fn ...) ...))
    767         #:with (e_c ...+) (stx-map (lambda (ec) (add-expected-ty ec #'t_expect)) #'(e_c_un ...))
    768         #:with (((x- ...) (e_guard- e_c-) (τ_guard τ_ec)) ...)
    769                (stx-map 
    770                    (λ (bs eg+ec) (infers/ctx+erase bs eg+ec)) 
    771                  #'(([x : τ] ...) ...) #'((e_guard e_c) ...))
    772         #:fail-unless (and (same-types? #'(τ_guard ...))
    773                            (Bool? (stx-car #'(τ_guard ...))))
    774                       "guard expression(s) must have type bool"
    775         #:with τ_out (stx-foldr (current-join) (stx-car #'(τ_ec ...)) (stx-cdr #'(τ_ec ...)))
    776         #:with z (generate-temporary) ; dont duplicate eval of test expr
    777         (⊢ (let- ([z e-])
    778              (cond- 
    779               [(and- (Cons? z) 
    780                      (let- ([x- (acc z)] ...) e_guard-))
    781                (let- ([x- (acc z)] ...) e_c-)] ...))
    782            : τ_out)])])])
    783 
    784 (define-syntax → ; wrapping →
    785   (syntax-parser
    786     [(_ ty ... #:TC TC ...)
    787      #'(∀ () (=> TC ... (ext-stlc:→ ty ...)))]
    788     [(_ Xs . rst)
    789      #:when (brace? #'Xs)
    790      #:with (X ...) #'Xs
    791      (syntax-property 
    792        #'(∀ (X ...)  (ext-stlc:→ . rst))
    793        'orig (list #'(→ . rst)))]
    794     [(_ . rst) (set-stx-prop/preserved #'(∀ () (ext-stlc:→ . rst)) 'orig (list #'(→ . rst)))]))
    795 ; special arrow that computes free vars; for use with tests
    796 ; (because we can't write explicit forall
    797 (define-syntax →/test 
    798   (syntax-parser
    799     [(_ (~and Xs (X:id ...)) . rst)
    800      #:when (brace? #'Xs)
    801      #'(∀ (X ...) (ext-stlc:→ . rst))]
    802     [(_ . rst)
    803      #:with Xs (compute-tyvars #'rst)
    804      #'(∀ Xs (ext-stlc:→ . rst))]))
    805 
    806 (define-syntax =>/test 
    807   (syntax-parser
    808     [(_ . (~and rst (TC ... (_arr . tys_arr))))
    809      #:with Xs (compute-tyvars #'rst)
    810      #'(∀ Xs (=> TC ... (ext-stlc:→ . tys_arr)))]))
    811 
    812 ; redefine these to use lifted →
    813 (provide (typed-out [+ : (→ Int Int Int)]
    814                     [- : (→ Int Int Int)]
    815                     [* : (→ Int Int Int)]
    816                     [max : (→ Int Int Int)]
    817                     [min : (→ Int Int Int)]
    818                     [void : (→ Unit)]
    819                     [= : (→ Int Int Bool)]
    820                     [<= : (→ Int Int Bool)]
    821                     [>= : (→ Int Int Bool)]
    822                     [< : (→ Int Int Bool)]
    823                     [> : (→ Int Int Bool)]
    824                     [modulo : (→ Int Int Int)]
    825                     [zero? : (→ Int Bool)]
    826                     [sub1 : (→ Int Int)]
    827                     [add1 : (→ Int Int)]
    828                     [not : (→ Bool Bool)]
    829                     [abs : (→ Int Int)]
    830                     [even? : (→ Int Bool)]
    831                     [odd? : (→ Int Bool)]))
    832 
    833 ;; λ --------------------------------------------------------------------------
    834 
    835 ; all λs have type (∀ (X ...) (→ τ_in ... τ_out)), even monomorphic fns
    836 (define-typed-syntax liftedλ #:export-as λ
    837   [(_ ([x:id (~datum :) ty] ... #:where TC ...) body)
    838    #:with (X ...) (compute-tyvars #'(ty ...))
    839    (syntax/loc stx (liftedλ {X ...} ([x : ty] ... #:where TC ...) body))]
    840   ;; TODO: I dont think this works for nested lambdas
    841   ;; ie, this will will re-infer tyvars X that should be bound by outer lam
    842   ;; - tyvars need to be bound in 2nd expand/df
    843   ;; - This is fixed in master by Alex
    844   [(_ (~and Xs (X ...)) ([x:id (~datum :) ty] ... #:where TC ...) body)
    845    #:when (brace? #'Xs)
    846    #:with (_ Xs+
    847            (_ () (_ () (_ () (_ () ; 2 let-stx = 4 let-values
    848             (_ (_ _ TC+ ...) 
    849                (_ _ ty+ ...)
    850                (_ op-tmps+
    851                 (_ () (_ ()
    852                  ((~literal #%expression)
    853                   (_ xs+
    854                    (_ () (_ () body+)))))))))))))
    855            (expand/df
    856             #'(lambda (X ...) 
    857                 (let-syntax 
    858                  ([X (make-rename-transformer (mk-type #'X))] ...)
    859                  (let-syntax
    860                   ;; must have this inner macro bc body of lambda may require
    861                   ;; ops defined by TC to be bound
    862                   ([a (syntax-parser [(_)
    863                     (syntax-parse (expand/df #'(void TC ...)) ; must expand in ctx of Xs
    864                       [(_ _ .
    865                         (~and (TC+ (... ...)) 
    866                               (~TCs ([op-sym ty-op] (... ...)) (... ...))))
    867                        ;; here, * suffix = flattened list
    868                        ;; op* ... = op-sym ... with proper ctx, and then flattened
    869                        #:with (op* (... ...))
    870                               (stx-appendmap 
    871                                 (lambda (os tc)
    872                                   (stx-map (lambda (o) (format-id tc "~a" o)) os))
    873                                 #'((op-sym (... ...)) (... ...)) #'(TC ...))
    874                        #:with (op-tmp* (... ...)) (generate-temporaries #'(op* (... ...)))
    875                        #:with (ty-op* (... ...)) (stx-flatten #'((ty-op (... ...)) (... ...)))
    876                        #:with ty-in-tagsss
    877                               (stx-map 
    878                                (syntax-parser
    879                                 [(~∀ _ fa-body)
    880                                  (get-type-tags
    881                                   (syntax-parse #'fa-body
    882                                    [(~ext-stlc:→ in (... ...) _) #'(in (... ...))]
    883                                    [(~=> _ (... ...) (~ext-stlc:→ in (... ...) _)) #'(in (... ...))]))])
    884                                #'(ty-op* (... ...)))
    885                          #:with (mangled-op (... ...)) (stx-map mangle #'(op* (... ...)) #'ty-in-tagsss)
    886                          #:with (y (... ...)) #'(x ...)
    887                          #:with (_ _ ty+ (... ...)) (expand/df #'(void ty ...))
    888                          #:with res
    889                          (expand/df 
    890                           #'(lambda (op-tmp* (... ...))
    891                              (let-syntax 
    892                               ([mangled-op 
    893                                 (make-rename-transformer (assign-type #'op-tmp* #'ty-op*))] (... ...))
    894                               (lambda (y (... ...))
    895                                (let-syntax
    896                                 ([y (make-rename-transformer (assign-type #'y #'ty+))] (... ...))
    897                                 body)))))
    898                          #'((void TC+ (... ...)) (void ty+ (... ...)) res)])])])
    899                       (a)))))
    900    #:with ty-out (typeof #'body+)
    901    #:with ty-out-expected (get-expected-type #'body+)
    902    #:fail-unless (or (not (syntax-e #'ty-out-expected))
    903                      (typecheck? #'ty-out #'ty-out-expected))
    904                  (type-error #:src #'body
    905                   #:msg "Body has type ~a, expected/given: ~a"
    906                   #'ty-out #'ty-out-expected)           
    907    (⊢ (λ op-tmps+ (λ xs+ body+)) 
    908       : (∀ Xs+ (=> TC+ ... (ext-stlc:→ ty+ ... ty-out))))]
    909   [(_ ([x:id (~datum :) ty] ...) body) ; no TC
    910    #:with (X ...) (compute-tyvars #'(ty ...))
    911    #:with (~∀ () (~ext-stlc:→ _ ... body-ty)) (get-expected-type stx)
    912    #'(Λ (X ...) (ext-stlc:λ ([x : ty] ...) (add-expected body body-ty)))]
    913   [(_ ([x:id (~datum :) ty] ...) body) ; no TC, ignoring expected-type
    914    #:with (X ...) (compute-tyvars #'(ty ...))
    915    #'(Λ (X ...) (ext-stlc:λ ([x : ty] ...) body))]
    916   [(_ (x:id ...+) body)
    917    #:with (~?∀ Xs expected) (get-expected-type stx)
    918    #:do [(unless (→? #'expected)
    919            (type-error #:src stx #:msg "λ parameters must have type annotations"))]
    920    #:with (~ext-stlc:→ arg-ty ... body-ty) #'expected
    921    #:do [(unless (stx-length=? #'[x ...] #'[arg-ty ...])
    922            (type-error #:src stx #:msg
    923                        (format "expected a function of ~a arguments, got one with ~a arguments"
    924                                (stx-length #'[arg-ty ...] #'[x ...]))))]
    925    #`(Λ Xs (ext-stlc:λ ([x : arg-ty] ...) #,(add-expected-ty #'body #'body-ty)))]
    926   #;[(_ args body)
    927    #:with (~∀ () (~ext-stlc:→ arg-ty ... body-ty)) (get-expected-type stx)
    928    #`(Λ () (ext-stlc:λ args #,(add-expected-ty #'body #'body-ty)))]
    929   #;[(_ (~and x+tys ([_ (~datum :) ty] ...)) . body)
    930    #:with Xs (compute-tyvars #'(ty ...))
    931    ;; TODO is there a way to have λs that refer to ids defined after them?
    932    #'(Λ Xs (ext-stlc:λ x+tys . body))])
    933 
    934 
    935 ;; #%app --------------------------------------------------
    936 (define-typed-syntax mlish:#%app #:export-as #%app
    937   [(_ e_fn . e_args)
    938 ;   #:when (printf "app: ~a\n" (syntax->datum #'(e_fn . e_args)))
    939    ;; ) compute fn type (ie ∀ and →) 
    940    #:with [e_fn- (~and ty_fn (~∀ Xs ty_fnX))] (infer+erase #'e_fn)
    941    (cond 
    942     [(stx-null? #'Xs)
    943      (define/with-syntax tyX_args
    944        (syntax-parse #'ty_fnX
    945          [(~ext-stlc:→ . tyX_args) #'tyX_args]))
    946      (syntax-parse #'(e_args tyX_args)
    947        [((e_arg ...) (τ_inX ... _))
    948         #:fail-unless (stx-length=? #'(e_arg ...) #'(τ_inX ...))
    949                       (mk-app-err-msg stx #:expected #'(τ_inX ...) 
    950                                       #:note "Wrong number of arguments.")
    951         #:with e_fn/ty (⊢ e_fn- : (ext-stlc:→ . tyX_args))
    952         #'(ext-stlc:#%app e_fn/ty (add-expected e_arg τ_inX) ...)])]
    953     [else
    954      (syntax-parse #'ty_fnX
    955       ;; TODO: combine these two clauses
    956       ;; no typeclasses, duplicate code for now --------------------------------
    957       [(~ext-stlc:→ . tyX_args) 
    958        ;; ) solve for type variables Xs
    959        (define/with-syntax ((e_arg1- ...) (unsolved-X ...) cs) (solve #'Xs #'tyX_args stx))
    960        ;; ) instantiate polymorphic function type
    961        (syntax-parse (inst-types/cs #'Xs #'cs #'tyX_args)
    962         [(τ_in ... τ_out) ; concrete types
    963          ;; ) arity check
    964          #:fail-unless (stx-length=? #'(τ_in ...) #'e_args)
    965                        (mk-app-err-msg stx #:expected #'(τ_in ...)
    966                         #:note "Wrong number of arguments.")
    967          ;; ) compute argument types; re-use args expanded during solve
    968          #:with ([e_arg2- τ_arg2] ...) (let ([n (stx-length #'(e_arg1- ...))])
    969                                         (infers+erase 
    970                                         (stx-map add-expected-ty 
    971                                           (stx-drop #'e_args n) (stx-drop #'(τ_in ...) n))))
    972          #:with (τ_arg1 ...) (stx-map typeof #'(e_arg1- ...))
    973          #:with (τ_arg ...) #'(τ_arg1 ... τ_arg2 ...)
    974          #:with (e_arg- ...) #'(e_arg1- ... e_arg2- ...)
    975          ;; ) typecheck args
    976          #:fail-unless (typechecks? #'(τ_arg ...) #'(τ_in ...))
    977                        (mk-app-err-msg stx 
    978                         #:given #'(τ_arg ...)
    979                         #:expected 
    980                         (stx-map 
    981                           (lambda (tyin) 
    982                             (define old-orig (get-orig tyin))
    983                             (define new-orig
    984                               (and old-orig
    985                                    (substs 
    986                                        (stx-map get-orig (lookup-Xs/keep-unsolved #'Xs #'cs)) #'Xs old-orig
    987                                        (lambda (x y) 
    988                                          (equal? (syntax->datum x) (syntax->datum y))))))
    989                             (syntax-property tyin 'orig (list new-orig)))
    990                           #'(τ_in ...)))
    991          #:with τ_out* (if (stx-null? #'(unsolved-X ...))
    992                            #'τ_out
    993                            (syntax-parse #'τ_out
    994                              [(~?∀ (Y ...) τ_out)
    995                               (unless (→? #'τ_out)
    996                                 (raise-app-poly-infer-error stx #'(τ_in ...) #'(τ_arg ...) #'e_fn))
    997                               #'(∀ (unsolved-X ... Y ...) τ_out)]))
    998          (⊢ (#%app- e_fn- e_arg- ...) : τ_out*)])]
    999       ;; handle type class constraints ----------------------------------------
   1000       [(~=> TCX ... (~ext-stlc:→ . tyX_args))
   1001        ;; ) solve for type variables Xs
   1002        (define/with-syntax ((e_arg1- ...) (unsolved-X ...) cs) (solve #'Xs #'tyX_args stx))
   1003        ;; ) instantiate polymorphic function type
   1004        (syntax-parse (inst-types/cs #'Xs #'cs #'((TCX ...) tyX_args))
   1005          [((TC ...) (τ_in ... τ_out)) ; concrete types
   1006           #:with (~TCs ([generic-op ty-concrete-op] ...) ...) #'(TC ...)
   1007           #:with (op ...)
   1008                  (stx-appendmap
   1009                    (lambda (gen-ops conc-op-tys TC)
   1010                      (map 
   1011                        (lambda (o tys)
   1012                          (with-handlers 
   1013                            ([exn:fail:syntax:unbound? 
   1014                              (lambda (e)
   1015                                (type-error #:src stx
   1016                                 #:msg 
   1017                                 (format 
   1018                                  (string-append
   1019                                      "~a instance undefined. "
   1020                                    "Cannot instantiate function with constraints "
   1021                                    "~a with:\n  ~a")
   1022                                  (type->str
   1023                                   (let* 
   1024                                    ([old-orig (get-orig TC)]
   1025                                     [new-orig
   1026                                      (and 
   1027                                       old-orig
   1028                                       (substs (stx-map get-orig (lookup-Xs/keep-unsolved #'Xs #'cs)) #'Xs old-orig
   1029                                               (lambda (x y) 
   1030                                                (equal? (syntax->datum x) 
   1031                                                        (syntax->datum y)))))])
   1032                                    (syntax-property TC 'orig (list new-orig))))
   1033                                  (types->str #'(TCX ...))
   1034                                  (string-join
   1035                                  (stx-map 
   1036                                    (lambda (X ty-solved)
   1037                                      (string-append (type->str X) " : " (type->str ty-solved)))
   1038                                    #'Xs (lookup-Xs/keep-unsolved #'Xs #'cs)) ", "))))])
   1039                          (lookup-op o tys)))
   1040                        (stx-map (lambda (o) (format-id stx "~a" o #:source stx)) gen-ops)
   1041                        (stx-map
   1042                          (syntax-parser
   1043                            [(~∀ _ (~ext-stlc:→ ty_in ... _)) #'(ty_in ...)])
   1044                          conc-op-tys)))
   1045                    #'((generic-op ...) ...) #'((ty-concrete-op ...) ...) #'(TC ...))
   1046           ;; ) arity check
   1047           #:fail-unless (stx-length=? #'(τ_in ...) #'e_args)
   1048                         (mk-app-err-msg stx #:expected #'(τ_in ...)
   1049                                         #:note "Wrong number of arguments.")
   1050           ;; ) compute argument types; re-use args expanded during solve
   1051           #:with ([e_arg2- τ_arg2] ...) (let ([n (stx-length #'(e_arg1- ...))])
   1052                                           (infers+erase 
   1053                                               (stx-map add-expected-ty 
   1054                                                 (stx-drop #'e_args n) (stx-drop #'(τ_in ...) n))))
   1055           #:with (τ_arg1 ...) (stx-map typeof #'(e_arg1- ...))
   1056           #:with (τ_arg ...) #'(τ_arg1 ... τ_arg2 ...)
   1057           #:with (e_arg- ...) #'(e_arg1- ... e_arg2- ...)
   1058           ;; ) typecheck args
   1059           #:fail-unless (typechecks? #'(τ_arg ...) #'(τ_in ...))
   1060                         (mk-app-err-msg stx 
   1061                          #:given #'(τ_arg ...)
   1062                          #:expected 
   1063                          (stx-map 
   1064                              (lambda (tyin) 
   1065                                (define old-orig (get-orig tyin))
   1066                                (define new-orig
   1067                                  (and old-orig
   1068                                       (substs 
   1069                                           (stx-map get-orig (lookup-Xs/keep-unsolved #'Xs #'cs)) #'Xs old-orig
   1070                                           (lambda (x y) 
   1071                                             (equal? (syntax->datum x) (syntax->datum y))))))
   1072                                (syntax-property tyin 'orig (list new-orig)))
   1073                            #'(τ_in ...)))
   1074          #:with τ_out* (if (stx-null? #'(unsolved-X ...))
   1075                            #'τ_out
   1076                            (syntax-parse #'τ_out
   1077                              [(~?∀ (Y ...) τ_out)
   1078                               (unless (→? #'τ_out)
   1079                                 (raise-app-poly-infer-error stx #'(τ_in ...) #'(τ_arg ...) #'e_fn))
   1080                               #'(∀ (unsolved-X ... Y ...) τ_out)]))
   1081           (⊢ ((#%app- e_fn- op ...) e_arg- ...) : τ_out*)])])])]
   1082   [(_ e_fn . e_args) ; err case; e_fn is not a function
   1083    #:with [e_fn- τ_fn] (infer+erase #'e_fn)
   1084    (type-error #:src stx 
   1085                #:msg (format "Expected expression ~a to have → type, got: ~a"
   1086                              (syntax->datum #'e_fn) (type->str #'τ_fn)))])
   1087 
   1088 
   1089 ;; cond and other conditionals
   1090 (define-typed-syntax cond
   1091   [(_ [(~or (~and (~datum else) (~parse test #'(ext-stlc:#%datum . #t)))
   1092          test)
   1093        b ... body] ...+)
   1094    #:with (test- ...) (⇑s (test ...) as Bool)
   1095    #:with ty-expected (get-expected-type stx)
   1096    #:with ([body- ty_body] ...) (infers+erase #'((add-expected body ty-expected) ...))
   1097    #:with (([b- ty_b] ...) ...) (stx-map infers+erase #'((b ...) ...))
   1098    #:with τ_out (stx-foldr (current-join) (stx-car #'(ty_body ...)) (stx-cdr #'(ty_body ...)))
   1099    (⊢ (cond- [test- b- ... body-] ...) : τ_out)])
   1100 (define-typed-syntax when
   1101   [(_ test body ...)
   1102 ;   #:with test- (⇑ test as Bool)
   1103    #:with [test- _] (infer+erase #'test)
   1104    #:with [(body- _) ...] (infers+erase #'(body ...))
   1105    (⊢ (when- test- body- ...) : Unit)])
   1106 (define-typed-syntax unless
   1107   [(_ test body ...)
   1108 ;   #:with test- (⇑ test as Bool)
   1109    #:with [test- _] (infer+erase #'test)
   1110    #:with [(body- _) ...] (infers+erase #'(body ...))
   1111    (⊢ (unless- test- body- ...) : Unit)])
   1112 
   1113 ;; sync channels and threads
   1114 (define-type-constructor Channel)
   1115 
   1116 (define-typed-syntax make-channel
   1117   [(_ (~and tys {ty}))
   1118    #:when (brace? #'tys)
   1119    (⊢ (make-channel-) : (Channel ty))])
   1120 (define-typed-syntax channel-get
   1121   [(_ c)
   1122    #:with (c- (ty)) (⇑ c as Channel)
   1123    (⊢ (channel-get- c-) : ty)])
   1124 (define-typed-syntax channel-put
   1125   [(_ c v)
   1126    #:with (c- (ty)) (⇑ c as Channel)
   1127    #:with [v- ty_v] (infer+erase #'v)
   1128    #:fail-unless (typechecks? #'ty_v #'ty)
   1129                  (format "Cannot send ~a value on ~a channel."
   1130                          (type->str #'ty_v) (type->str #'ty))
   1131    (⊢ (channel-put- c- v-) : Unit)])
   1132 
   1133 (define-base-type Thread)
   1134 
   1135 ;; threads
   1136 (define-typed-syntax thread
   1137   [(_ th)
   1138    #:with (th- (~∀ () (~ext-stlc:→ τ_out))) (infer+erase #'th)
   1139    (⊢ (thread- th-) : Thread)])
   1140 
   1141 (provide (typed-out [random : (→ Int Int)]
   1142                     [integer->char : (→ Int Char)]
   1143                     [string->list : (→ String (List Char))]
   1144                     [string->number : (→ String Int)]))
   1145 (define-typed-syntax num->str #:export-as number->string
   1146  [f:id (assign-type #'number->string #'(→ Int String))]
   1147  [(_ n)
   1148   #'(num->str n (ext-stlc:#%datum . 10))]
   1149  [(_ n rad)
   1150   #:with args- (⇑s (n rad) as Int)
   1151   (⊢ (number->string- . args-) : String)])
   1152 (provide (typed-out [string : (→ Char String)]
   1153                     [sleep : (→ Int Unit)]
   1154                     [string=? : (→ String String Bool)]
   1155                     [string<? : (→ String String Bool)]
   1156                     [string<=? : (→ String String Bool)]
   1157                     [string>? : (→ String String Bool)]
   1158                     [string>=? : (→ String String Bool)]
   1159                     [char=? : (→ Char Char Bool)]
   1160                     [char<? : (→ Char Char Bool)]
   1161                     [char<=? : (→ Char Char Bool)]
   1162                     [char>? : (→ Char Char Bool)]
   1163                     [char>=? : (→ Char Char Bool)]))
   1164 
   1165 (define-typed-syntax string-append
   1166   [(_ . strs)
   1167    #:with strs- (⇑s strs as String)
   1168    (⊢ (string-append- . strs-) : String)])
   1169 
   1170 ;; vectors
   1171 (define-type-constructor Vector)
   1172 
   1173 (define-typed-syntax vector
   1174   [(_ (~and tys {ty}))
   1175    #:when (brace? #'tys)
   1176    (⊢ (vector-) : (Vector ty))]
   1177   [(_ v ...)
   1178    #:with ([v- ty] ...) (infers+erase #'(v ...))
   1179    #:when (same-types? #'(ty ...))
   1180    #:with one-ty (stx-car #'(ty ...))
   1181    (⊢ (vector- v- ...) : (Vector one-ty))])
   1182 (define-typed-syntax make-vector/tc #:export-as make-vector
   1183   [(_ n) #'(make-vector/tc n (ext-stlc:#%datum . 0))]
   1184   [(_ n e)
   1185    #:with n- (⇑ n as Int)
   1186    #:with [e- ty] (infer+erase #'e)
   1187    (⊢ (make-vector- n- e-) : (Vector ty))])
   1188 (define-typed-syntax vector-length
   1189   [(_ e)
   1190    #:with [e- _] (⇑ e as Vector)
   1191    (⊢ (vector-length- e-) : Int)])
   1192 (define-typed-syntax vector-ref
   1193   [(_ e n)
   1194    #:with n- (⇑ n as Int)
   1195    #:with [e- (ty)] (⇑ e as Vector)
   1196    (⊢ (vector-ref- e- n-) : ty)])
   1197 (define-typed-syntax vector-set!
   1198   [(_ e n v)
   1199    #:with n- (⇑ n as Int)
   1200    #:with [e- (ty)] (⇑ e as Vector)
   1201    #:with [v- ty_v] (infer+erase #'v)
   1202    #:when (typecheck? #'ty_v #'ty)
   1203    (⊢ (vector-set!- e- n- v-) : Unit)])
   1204 (define-typed-syntax vector-copy!
   1205   [(_ dest start src)
   1206    #:with start- (⇑ start as Int)
   1207    #:with [dest- (ty_dest)] (⇑ dest as Vector)
   1208    #:with [src- (ty_src)] (⇑ src as Vector)
   1209    #:when (typecheck? #'ty_dest #'ty_src)
   1210    (⊢ (vector-copy!- dest- start- src-) : Unit)])
   1211 
   1212 
   1213 ;; sequences and for loops
   1214 
   1215 (define-type-constructor Sequence)
   1216 
   1217 (define-typed-syntax in-range/tc #:export-as in-range
   1218   [(_ end)
   1219    #'(in-range/tc (ext-stlc:#%datum . 0) end (ext-stlc:#%datum . 1))]
   1220   [(_ start end)
   1221    #'(in-range/tc start end (ext-stlc:#%datum . 1))]
   1222   [(_ start end step)
   1223    #:with (e- ...) (⇑s (start end step) as Int)
   1224    (⊢ (in-range- e- ...) : (Sequence Int))])
   1225 
   1226 (define-typed-syntax in-naturals/tc #:export-as in-naturals
   1227  [(_) #'(in-naturals/tc (ext-stlc:#%datum . 0))]
   1228  [(_ start)
   1229   #:with start- (⇑ start as Int)
   1230   (⊢ (in-naturals- start-) : (Sequence Int))])
   1231  
   1232 
   1233 (define-typed-syntax in-vector
   1234   [(_ e)
   1235    #:with [e- (ty)] (⇑ e as Vector)
   1236    (⊢ (in-vector- e-) : (Sequence ty))])
   1237 
   1238 (define-typed-syntax in-list
   1239   [(_ e)
   1240    #:with [e- (ty)] (⇑ e as List)
   1241    (⊢ (in-list- e-) : (Sequence ty))])
   1242 
   1243 (define-typed-syntax in-lines
   1244   [(_ e)
   1245    #:with e- (⇑ e as String)
   1246    (⊢ (in-lines- (open-input-string- e-)) : (Sequence String))])
   1247 
   1248 (define-typed-syntax for
   1249   [(_ ([x:id e]...) b ... body)
   1250    #:with ([e- (ty)] ...) (⇑s (e ...) as Sequence)
   1251    #:with [(x- ...) (b- ... body-) (ty_b ... ty_body)] 
   1252           (infers/ctx+erase #'([x : ty] ...) #'(b ... body))
   1253    (⊢ (for- ([x- e-] ...) b- ... body-) : Unit)])
   1254 (define-typed-syntax for*
   1255   [(_ ([x:id e]...) body)
   1256    #:with ([e- (ty)] ...) (⇑s (e ...) as Sequence)
   1257    #:with [(x- ...) body- ty_body] (infer/ctx+erase #'([x : ty] ...) #'body)
   1258    (⊢ (for*- ([x- e-] ...) body-) : Unit)])
   1259 
   1260 (define-typed-syntax for/list
   1261   [(_ ([x:id e]...) body)
   1262    #:with ([e- (ty)] ...) (⇑s (e ...) as Sequence)
   1263    #:with [(x- ...) body- ty_body] (infer/ctx+erase #'([x : ty] ...) #'body)
   1264    (⊢ (for/list- ([x- e-] ...) body-) : (List ty_body))])
   1265 (define-typed-syntax for/vector
   1266   [(_ ([x:id e]...) body)
   1267    #:with ([e- (ty)] ...) (⇑s (e ...) as Sequence)
   1268    #:with [(x- ...) body- ty_body] (infer/ctx+erase #'([x : ty] ...) #'body)
   1269    (⊢ (for/vector- ([x- e-] ...) body-) : (Vector ty_body))])
   1270 (define-typed-syntax for*/vector
   1271   [(_ ([x:id e]...) body)
   1272    #:with ([e- (ty)] ...) (⇑s (e ...) as Sequence)
   1273    #:with [(x- ...) body- ty_body] (infer/ctx+erase #'([x : ty] ...) #'body)
   1274    (⊢ (for*/vector- ([x- e-] ...) body-) : (Vector ty_body))])
   1275 (define-typed-syntax for*/list
   1276   [(_ ([x:id e]...) body)
   1277    #:with ([e- (ty)] ...) (⇑s (e ...) as Sequence)
   1278    #:with [(x- ...) body- ty_body] (infer/ctx+erase #'([x : ty] ...) #'body)
   1279    (⊢ (for*/list- ([x- e-] ...) body-) : (List ty_body))])
   1280 (define-typed-syntax for/fold
   1281   [(_ ([acc init]) ([x:id e] ...) body)
   1282    #:with [init- ty_init] (infer+erase #`(pass-expected init #,stx))
   1283    #:with ([e- (ty)] ...) (⇑s (e ...) as Sequence)
   1284    #:with [(acc- x- ...) body- ty_body] 
   1285           (infer/ctx+erase #'([acc : ty_init][x : ty] ...) #'body)
   1286    #:fail-unless (typecheck? #'ty_body #'ty_init)
   1287                  (type-error #:src stx
   1288                   #:msg 
   1289                   "for/fold: Type of body and initial accumulator must be the same, given ~a and ~a"
   1290                   #'ty_init #'ty_body)
   1291    (⊢ (for/fold- ([acc- init-]) ([x- e-] ...) body-) : ty_body)])
   1292 
   1293 (define-typed-syntax for/hash
   1294   [(_ ([x:id e]...) body)
   1295    #:with ([e- (ty)] ...) (⇑s (e ...) as Sequence)
   1296    #:with [(x- ...) body- (~× ty_k ty_v)] 
   1297           (infer/ctx+erase #'([x : ty] ...) #'body)
   1298    (⊢ (for/hash- ([x- e-] ...) (let- ([t body-]) (values- (car- t) (cadr- t))))
   1299         : (Hash ty_k ty_v))])
   1300 
   1301 (define-typed-syntax for/sum
   1302   [(_ ([x:id e]... 
   1303        (~optional (~seq #:when guard) #:defaults ([guard #'#t])))
   1304       body)
   1305    #:with ([e- (ty)] ...) (⇑s (e ...) as Sequence)
   1306    #:with [(x- ...) (guard- body-) (_ ty_body)]
   1307           (infers/ctx+erase #'([x : ty] ...) #'(guard body))
   1308    #:when (Int? #'ty_body)
   1309    (⊢ (for/sum- ([x- e-] ... #:when guard-) body-) : Int)])
   1310 
   1311 ; printing and displaying
   1312 (define-typed-syntax printf
   1313   [(_ str e ...)
   1314    #:with s- (⇑ str as String)
   1315    #:with ([e- ty] ...) (infers+erase #'(e ...))
   1316    (⊢ (printf- s- e- ...) : Unit)])
   1317 (define-typed-syntax format
   1318   [(_ str e ...)
   1319    #:with s- (⇑ str as String)
   1320    #:with ([e- ty] ...) (infers+erase #'(e ...))
   1321    (⊢ (format- s- e- ...) : String)])
   1322 (define-typed-syntax display
   1323   [(_ e)
   1324    #:with [e- _] (infer+erase #'e)
   1325    (⊢ (display- e-) : Unit)])
   1326 (define-typed-syntax displayln
   1327   [(_ e)
   1328    #:with [e- _] (infer+erase #'e)
   1329    (⊢ (displayln- e-) : Unit)])
   1330 (provide (typed-out [newline : (→ Unit)]))
   1331 
   1332 (define-typed-syntax list->vector
   1333   [(_ e)
   1334    #:with [e- (ty)] (⇑ e as List)
   1335    (⊢ (list->vector- e-) : (Vector ty))])
   1336 
   1337 (define-typed-syntax let
   1338   [(_ name:id (~datum :) ty:type ~! ([x:id e] ...) b ... body)
   1339    #:with ([e- ty_e] ...) (infers+erase #'(e ...))
   1340    #:with [(name- . xs-) (body- ...) (_ ... ty_body)] 
   1341           (infers/ctx+erase #'([name : (→ ty_e ... ty.norm)][x : ty_e] ...) 
   1342                             #'(b ... body))
   1343    #:fail-unless (typecheck? #'ty_body #'ty.norm)
   1344                  (format "type of let body ~a does not match expected typed ~a"
   1345                          (type->str #'ty_body) (type->str #'ty))
   1346    (⊢ (letrec- ([name- (λ- xs- body- ...)]) 
   1347         (name- e- ...))
   1348       : ty_body)]
   1349   [(_ ([x:id e] ...) body ...) 
   1350    #'(ext-stlc:let ([x e] ...) (begin/tc body ...))])
   1351 (define-typed-syntax let*
   1352   [(_ ([x:id e] ...) body ...) 
   1353    #'(ext-stlc:let* ([x e] ...) (begin/tc body ...))])
   1354 
   1355 (define-typed-syntax begin/tc #:export-as begin
   1356  [(_ body ... b)
   1357   #:with expected (get-expected-type stx)
   1358   #:with b_ann #'(add-expected b expected)
   1359   #'(ext-stlc:begin body ... b_ann)])
   1360 
   1361 ;; hash
   1362 (define-type-constructor Hash #:arity = 2)
   1363 
   1364 (define-typed-syntax in-hash
   1365   [(_ e)
   1366    #:with [e- (ty_k ty_v)] (⇑ e as Hash)
   1367    (⊢ (map- (λ- (k+v) (list- (car- k+v) (cdr- k+v))) (hash->list- e-)) 
   1368 ;   (⊢ (hash->list e-)
   1369       : (Sequence (stlc+rec-iso:× ty_k ty_v)))])
   1370 
   1371 ; mutable hashes
   1372 (define-typed-syntax hash
   1373   [(_ (~and tys {ty_key ty_val}))
   1374    #:when (brace? #'tys)
   1375    (⊢ (make-hash-) : (Hash ty_key ty_val))]
   1376   [(_ (~seq k v) ...)
   1377    #:with ([k- ty_k] ...) (infers+erase #'(k ...))
   1378    #:with ([v- ty_v] ...) (infers+erase #'(v ...))
   1379    #:when (same-types? #'(ty_k ...))
   1380    #:when (same-types? #'(ty_v ...))
   1381    #:with ty_key (stx-car #'(ty_k ...))
   1382    #:with ty_val (stx-car #'(ty_v ...))
   1383    (⊢ (make-hash- (list- (cons- k- v-) ...)) : (Hash ty_key ty_val))])
   1384 (define-typed-syntax hash-set!
   1385   [(_ h k v)
   1386    #:with [h- (ty_key ty_val)] (⇑ h as Hash)
   1387    #:with [k- ty_k] (infer+erase #'k)
   1388    #:with [v- ty_v] (infer+erase #'v)
   1389    #:when (typecheck? #'ty_k #'ty_key)
   1390    #:when (typecheck? #'ty_v #'ty_val)
   1391    (⊢ (hash-set!- h- k- v-) : Unit)])
   1392 (define-typed-syntax hash-ref/tc #:export-as hash-ref
   1393   [(_ h k) #'(hash-ref/tc h k (ext-stlc:#%datum . #f))]
   1394   [(_ h k fail)
   1395    #:with [h- (ty_key ty_val)] (⇑ h as Hash)
   1396    #:with [k- ty_k] (infer+erase #'k)
   1397    #:when (typecheck? #'ty_k #'ty_key)
   1398    #:with (fail- _) (infer+erase #'fail) ; default val can be any
   1399    (⊢ (hash-ref- h- k- fail-) : ty_val)])
   1400 (define-typed-syntax hash-has-key?
   1401   [(_ h k)
   1402    #:with [h- (ty_key _)] (⇑ h as Hash)
   1403    #:with [k- ty_k] (infer+erase #'k)
   1404    #:when (typecheck? #'ty_k #'ty_key)
   1405    (⊢ (hash-has-key?- h- k-) : Bool)])
   1406 
   1407 (define-typed-syntax hash-count
   1408   [(_ h)
   1409    #:with [h- _] (⇑ h as Hash)
   1410    (⊢ (hash-count- h-) : Int)])
   1411 
   1412 (define-base-type String-Port)
   1413 (define-base-type Input-Port)
   1414 (provide (typed-out [open-output-string : (→ String-Port)]
   1415                     [get-output-string : (→ String-Port String)]
   1416                     [string-upcase : (→ String String)]))
   1417 
   1418 (define-typed-syntax write-string/tc #:export-as write-string
   1419  [(_ str out)
   1420   #'(write-string/tc str out (ext-stlc:#%datum . 0) (string-length/tc str))]
   1421  [(_ str out start end)
   1422    #:with str- (⇑ str as String)
   1423    #:with out- (⇑ out as String-Port)
   1424    #:with start- (⇑ start as Int)
   1425    #:with end- (⇑ end as Int)
   1426    (⊢ (write-string- str- out- start- end-) : Unit)])
   1427 
   1428 (define-typed-syntax string-length/tc #:export-as string-length
   1429  [(_ str) 
   1430   #:with str- (⇑ str as String)
   1431   (⊢ (string-length- str-) : Int)])
   1432 (provide (typed-out [make-string : (→ Int String)]
   1433                     [string-set! : (→ String Int Char Unit)]
   1434                     [string-ref : (→ String Int Char)]))
   1435 (define-typed-syntax string-copy!/tc #:export-as string-copy!
   1436   [(_ dest dest-start src)
   1437    #'(string-copy!/tc 
   1438       dest dest-start src (ext-stlc:#%datum . 0) (string-length/tc src))]
   1439   [(_ dest dest-start src src-start src-end)
   1440    #:with dest- (⇑ dest as String)
   1441    #:with src- (⇑ src as String)
   1442    #:with dest-start- (⇑ dest-start as Int)
   1443    #:with src-start- (⇑ src-start as Int)
   1444    #:with src-end- (⇑ src-end as Int)
   1445    (⊢ (string-copy!- dest- dest-start- src- src-start- src-end-) : Unit)])
   1446 
   1447 (provide (typed-out [fl+ : (→ Float Float Float)]
   1448                     [fl- : (→ Float Float Float)]
   1449                     [fl* : (→ Float Float Float)]
   1450                     [fl/ : (→ Float Float Float)]
   1451                     [fl= : (→ Float Float Bool)]
   1452                     [flsqrt : (→ Float Float)]
   1453                     [flceiling : (→ Float Float)]
   1454                     [inexact->exact : (→ Float Int)]
   1455                     [exact->inexact : (→ Int Float)]
   1456                     [char->integer : (→ Char Int)]
   1457                     [real->decimal-string : (→ Float Int String)]
   1458                     [fx->fl : (→ Int Float)]))
   1459 (define-typed-syntax quotient+remainder
   1460   [(_ x y)
   1461    #:with x- (⇑ x as Int)
   1462    #:with y- (⇑ y as Int)
   1463    (⊢ (call-with-values- (λ- () (quotient/remainder- x- y-)) list-)
   1464       : (stlc+rec-iso:× Int Int))])
   1465 (provide (typed-out [quotient : (→ Int Int Int)]))
   1466 
   1467 (define-typed-syntax set!
   1468  [(_ x:id e)
   1469   #:with [x- ty_x] (infer+erase #'x)
   1470   #:with [e- ty_e] (infer+erase #'e)
   1471   #:when (typecheck? #'ty_e #'ty_x)
   1472   (⊢ (set!- x e-) : Unit)])
   1473 
   1474 (define-typed-syntax provide-type [(_ ty ...) #'(provide- ty ...)])
   1475 
   1476 (define-typed-syntax mlish-provide #:export-as provide
   1477   [(_ x:id ...)
   1478    #:with ([x- ty_x] ...) (infers+erase #'(x ...))
   1479    ; TODO: use hash-code to generate this tmp
   1480    #:with (x-ty ...) (stx-map (lambda (y) (format-id y "~a-ty" y)) #'(x ...)) 
   1481    #'(begin-
   1482        (provide- x ...)
   1483        (stlc+rec-iso:define-type-alias x-ty ty_x) ...
   1484        (provide- x-ty ...))])
   1485 (define-typed-syntax require-typed
   1486   [(_ x:id ... #:from mod)
   1487    #:with (x-ty ...) (stx-map (lambda (y) (format-id y "~a-ty" y)) #'(x ...))
   1488    #:with (y ...) (generate-temporaries #'(x ...))
   1489    #'(begin-
   1490        (require- (rename-in- (only-in- mod x ... x-ty ...) [x y] ...))
   1491        (define-syntax- x (make-rename-transformer (assign-type #'y #'x-ty))) ...)])
   1492 
   1493 (define-base-type Regexp)
   1494 (provide (typed-out [regexp-match : (→ Regexp String (List String))]
   1495                     [regexp : (→ String Regexp)]))
   1496 
   1497 (define-typed-syntax equal?
   1498   [(_ e1 e2)
   1499    #:with [e1- ty1] (infer+erase #'e1)
   1500    #:with [e2- ty2] (infer+erase #'(add-expected e2 ty1))
   1501    #:fail-unless (typecheck? #'ty1 #'ty2) "arguments to equal? have different types"
   1502    (⊢ (equal?- e1- e2-) : Bool)])
   1503 
   1504 (define-syntax (inst stx)
   1505   (syntax-parse stx
   1506     [(_ e ty ...)
   1507      #:with [ee tyty] (infer+erase #'e)
   1508      #:with [e- ty_e] (infer+erase #'(sysf:inst e ty ...))
   1509      #:with ty_out (cond
   1510                     [(→? #'ty_e) #'(∀ () ty_e)]
   1511                     [(=>? #'ty_e) #'(∀ () ty_e)]
   1512                     [else #'ty_e])
   1513      (⊢ e- : ty_out)]))
   1514 
   1515 (define-typed-syntax read
   1516   [(_)
   1517    (⊢ (let- ([x (read-)])
   1518         (cond- [(eof-object?- x) ""]
   1519               [(number?- x) (number->string- x)]
   1520               [(symbol?- x) (symbol->string- x)])) : String)])
   1521 
   1522 (begin-for-syntax
   1523  ;; - this function should be wrapped with err handlers,
   1524  ;; for when an op with the specified generic op and input types does not exist,
   1525  ;; otherwise, will get "unbound id" err with internal mangled id
   1526  ;; - gen-op must be identifier, eg should already have proper context
   1527  ;; and mangled-op is selected based on input types,
   1528  ;; ie, dispatch to different concrete fns based on input tpyes
   1529  ;; TODO: currently using input types only, but sometimes may need output type
   1530  ;; eg, Read typeclass, this is currently unsupported
   1531  ;; - need to use expected-type?
   1532  (define (lookup-op gen-op tys)
   1533   (define (transfer-gen-op-ctx o) (format-id gen-op "~a" o))
   1534   (define (transfer-gen-op-ctxs os) (stx-map transfer-gen-op-ctx os))
   1535   (syntax-parse tys
   1536    ;; TODO: for now, only handle uniform tys, ie tys must be all
   1537    ;;  tycons or all base types or all tyvars
   1538    ;; tycon --------------------------------------------------
   1539    ;; - recur on ty-args
   1540    [(((~literal #%plain-app) tycon
   1541      ((~literal #%plain-lambda) _ _ ty-arg ...)) ...)
   1542     ;; 1) look up concrete op corresponding to generic op and input tys
   1543     #:with mangled (mangle gen-op #'(tycon ...))
   1544     #:with [conc-op ty-conc-op] (infer+erase #'mangled)
   1545     ;; compute sub-ops based on TC constraints (will include gen-op --- for smaller type)
   1546     #:with (~∀ Xs (~=> TC ... (~ext-stlc:→ . ty-args))) #'ty-conc-op
   1547     #:with (~TCs ([op _] ...) ...) #'(TC ...) ; order matters, must match order of arg types
   1548     #:with ((sub-op ...) ...) (stx-map transfer-gen-op-ctxs #'((op ...) ...))
   1549     ;; drop the TCs in result type, the proper subops are already applied
   1550     #:with ty-conc-op-noTC #'(∀ Xs (ext-stlc:→ . ty-args))
   1551     ;; recursively call lookup-op for each subop and input ty-args
   1552     (⊢ (conc-op 
   1553          #,@(apply stx-appendmap (lambda (ops . tys) (stx-map (lambda (o) (lookup-op o tys)) ops))
   1554                    #'((sub-op ...) ...)
   1555                    (syntax->list #'((ty-arg ...) ...))))
   1556        : ty-conc-op-noTC)]
   1557    ;; base type --------------------------------------------------
   1558    [(((~literal #%plain-app) tag) ...) (expand/df (mangle gen-op #'(tag ...)))]
   1559    ;; tyvars --------------------------------------------------
   1560    [_ (expand/df (mangle gen-op tys))]))
   1561  (define (get-fn-ty-in-tags ty-fn)
   1562    (syntax-parse ty-fn
   1563      [(~∀ _ (~ext-stlc:→ ty_in ... _))
   1564       (get-type-tags #'(ty_in ...))]))
   1565  (define (TC-exists? TC #:ctx [ctx TC]) ; throws exn if fail
   1566    (syntax-parse TC
   1567      [(~TC-base [gen-op ty-op] . _) ; only need 1st op
   1568       (with-handlers 
   1569         ([exn:fail:syntax:unbound? 
   1570            (lambda (e) 
   1571              (type-error #:src ctx
   1572                          #:msg "No instance defined for ~a" TC))])
   1573       (expand/df
   1574         (mangle (format-id ctx "~a" #'gen-op)
   1575                 (get-fn-ty-in-tags #'ty-op))))]))
   1576  (define (TCs-exist? TCs #:ctx [ctx TCs])
   1577    (stx-map (lambda (tc) (TC-exists? tc #:ctx ctx)) TCs)))
   1578 
   1579 ;; adhoc polymorphism
   1580 ;; TODO: make this a formal type?
   1581 ;; - or at least define a pattern expander - DONE 2016-05-01
   1582 ;; A TC is a #'(=> subclassTC ... ([generic-op gen-op-ty] ...))
   1583 (define-syntax (define-typeclass stx)
   1584   (syntax-parse stx
   1585     [(~or (_ TC ... (~datum =>) (Name X ...) [op (~datum :) ty] ...)
   1586           (~and (_ (Name X ...) [op (~datum :) ty] ...) ; no subclass
   1587                 (~parse (TC ...) #'())))
   1588      #'(begin-
   1589          (define-syntax- (op stx)
   1590            (syntax-parse stx
   1591              [(o . es)
   1592               #:with ([e- ty_e] (... ...)) (infers+erase #'es)
   1593               #:with out-op 
   1594                      (with-handlers 
   1595                        ([exn:fail:syntax:unbound? 
   1596                          (lambda (e) 
   1597                            (type-error #:src #'o
   1598                             #:msg (format 
   1599                                    "~a operation undefined for input types: ~a"
   1600                                    (syntax->datum #'o) 
   1601                                    (types->str #'(ty_e (... ...))))))])
   1602                        (lookup-op #'o #'(ty_e (... ...))))
   1603               #:with app (datum->syntax #'o '#%app)
   1604               (datum->syntax stx (cons #'app (cons #'out-op #'(e- (... ...)))))])) ...
   1605          (define-syntax- (Name stx)
   1606            (syntax-parse stx
   1607              [(_ X ...) 
   1608               (add-orig 
   1609                 #`(=> TC ... #,(mk-type #'(('op ty) ...)))
   1610                 #'(Name X ...))])))]))
   1611 
   1612 (define-syntax (define-instance stx)
   1613   (syntax-parse stx
   1614     ;; base type, possibly with subclasses  ------------------------------------
   1615     [(_ (Name ty ...) [generic-op concrete-op] ...)
   1616      #:with (~=> TC ... (~TC [generic-op-expected ty-concrete-op-expected] ...))
   1617             (expand/df #'(Name ty ...))
   1618      #:when (TCs-exist? #'(TC ...) #:ctx stx)
   1619      #:fail-unless (set=? (syntax->datum #'(generic-op ...)) 
   1620                           (syntax->datum #'(generic-op-expected ...)))
   1621                    (type-error #:src stx
   1622                     #:msg (format "Type class instance ~a incomplete, missing: ~a"
   1623                             (syntax->datum #'(Name ty ...))
   1624                             (string-join
   1625                              (map symbol->string 
   1626                               (set-subtract (syntax->datum #'(generic-op-expected ...)) 
   1627                                             (syntax->datum #'(generic-op ...))))
   1628                              ", ")))
   1629      ;; sort, using order from define-typeclass
   1630      #:with ([generic-op-sorted concrete-op-sorted] ...) 
   1631             (stx-map
   1632               (lambda (expected-op) 
   1633                   (stx-findf
   1634                     (lambda (gen+conc) 
   1635                       (equal? (syntax->datum (stx-car gen+conc)) 
   1636                               (syntax->datum expected-op)))
   1637                   #'([generic-op concrete-op] ...)))
   1638               #'(generic-op-expected ...))
   1639      ;; typecheck type of given concrete-op with expected type from define-typeclass
   1640      #:with ([concrete-op+ ty-concrete-op] ...) (infers+erase #'(concrete-op-sorted ...))
   1641      #:fail-unless (typechecks? #'(ty-concrete-op ...) #'(ty-concrete-op-expected ...))
   1642                    (mk-app-err-msg (syntax/loc stx (#%app (Name ty ...) concrete-op ...))
   1643                      #:expected #'(ty-concrete-op-expected ...)
   1644                      #:given #'(ty-concrete-op ...)
   1645                      #:action "defining typeclass instance"
   1646                      #:name (format "~a" (syntax->datum #'(Name ty ...))))
   1647      ;; generate mangled name from tags in input types
   1648      #:with (ty_in-tags ...) 
   1649             (stx-map 
   1650               (syntax-parser
   1651                 [(~∀ _ (~ext-stlc:→ ty_in ... _))
   1652                  (get-type-tags #'(ty_in ...))])
   1653               #'(ty-concrete-op-expected ...))
   1654      ;; use input types
   1655      #:with (mangled-op ...) (stx-map mangle #'(generic-op ...) #'(ty_in-tags ...))
   1656      #'(begin-
   1657          (define-syntax- (mangled-op stx) 
   1658            (syntax-parse stx [_:id (assign-type #'concrete-op+ #'ty-concrete-op-expected)]))
   1659          ...)]
   1660     ;; tycon, possibly with subclasses -----------------------------------------
   1661     [(_ TC ... (~datum =>) (Name ty ...) [generic-op concrete-op] ...)
   1662      #:with (X ...) (compute-tyvars #'(ty ...))
   1663      ;; ok to drop TCsub ...? I think yes
   1664      ;; - the same TCsubs will be part of TC+,
   1665      ;;   so proper op will be looked up, depending on input args, 
   1666      ;;   using inherited ops in TC+
   1667      ;; This is assuming Name and TC ... are the same typeclass
   1668      ;; Won't work for, eg (TC1 (List X)) that depends on some other (TC2 X)
   1669      #:with (Xs+ 
   1670              (TC+ ... 
   1671               (~=> TCsub ... 
   1672                    (~TC [generic-op-expected ty-concrete-op-expected] ...)))
   1673              _)
   1674             (infers/tyctx+erase #'([X :: #%type] ...) #'(TC ... (Name ty ...)))
   1675      #:when (TCs-exist? #'(TCsub ...) #:ctx stx)
   1676      ;; simulate as if the declared concrete-op* has TC ... predicates
   1677      ;; TODO: fix this manual deconstruction and assembly
   1678      #:with ((app fa (lam _ ei ty_fn)) ...) #'(ty-concrete-op-expected ...)
   1679      #:with (ty-concrete-op-expected-withTC ...) 
   1680             (stx-map (current-type-eval) #'((app fa (lam Xs+ ei (=> TC+ ... ty_fn))) ...))
   1681      #:fail-unless (set=? (syntax->datum #'(generic-op ...)) 
   1682                           (syntax->datum #'(generic-op-expected ...)))
   1683                    (type-error #:src stx
   1684                     #:msg (format "Type class instance ~a incomplete, missing: ~a"
   1685                             (syntax->datum #'(Name ty ...))
   1686                             (string-join
   1687                              (map symbol->string 
   1688                               (set-subtract (syntax->datum #'(generic-op-expected ...)) 
   1689                                             (syntax->datum #'(generic-op ...))))
   1690                              ", ")))
   1691      ;; - sort, using order from define-typeclass
   1692      ;; - insert TC ... if lambda
   1693      #:with ([generic-op-sorted concrete-op-sorted] ...) 
   1694             (stx-map
   1695               (lambda (expected-op) 
   1696                 (syntax-parse
   1697                   (stx-findf
   1698                     (lambda (gen+conc) 
   1699                       (equal? (syntax->datum (stx-car gen+conc)) 
   1700                               (syntax->datum expected-op)))
   1701                   #'([generic-op concrete-op] ...))
   1702                   [(g c) 
   1703                    (syntax-parse #'c
   1704                      ;; add TCs to (unexpanded) lambda
   1705                      [((~and lam (~literal liftedλ)) (args ...) . body) 
   1706                       #'(g (lam (args ... #:where TC ...) . body))]
   1707                      [_ #'(g c)])]))
   1708               #'(generic-op-expected ...))
   1709      ;; ;; for now, dont expand (and typecheck) concrete-op
   1710      ;; #:with ([concrete-op+ ty-concrete-op] ...) (infers+erase #'(concrete-op ...))
   1711      ;; #:when (typechecks? #'(ty-concrete-op ...) #'(ty-concrete-op-expected ...))
   1712      ;; TODO: right now, dont recur to get nested tags
   1713      ;; but may need to do so, ie if an instance needs to define more than one concrete op,
   1714      ;; eg (define-instance (Eq (List Int)) ...)
   1715      #:with (ty_in-tags ...) 
   1716             (stx-map 
   1717               (syntax-parser
   1718                 [(~∀ _ (~ext-stlc:→ ty_in ... _))
   1719                  (get-type-tags #'(ty_in ...))]
   1720                 #;[(~∀ _ (~=> _ ... (~ext-stlc:→ ty_in ... _)))
   1721                  (get-type-tags #'(ty_in ...))])
   1722               #'(ty-concrete-op-expected ...))
   1723      #:with (mangled-op ...) (stx-map mangle #'(generic-op ...) #'(ty_in-tags ...))
   1724      ;; need a name for concrete-op because concrete-op and generic-op may be
   1725      ;; mutually recursive, eg (Eq (List X))
   1726      #:with (f ...) (generate-temporaries #'(concrete-op-sorted ...))
   1727      #'(begin-
   1728          (define- f concrete-op-sorted) ...
   1729          (define-syntax- (mangled-op stx) 
   1730            (syntax-parse stx [_:id (assign-type #'f #'ty-concrete-op-expected-withTC)]))
   1731          ...)]))