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 ...)]))