[overload] now improved with identifier macros

This commit is contained in:
Ben Greenman 2015-10-22 15:20:16 -04:00
parent c299e58a04
commit e038d220f1
2 changed files with 58 additions and 60 deletions

View File

@ -1,15 +1,9 @@
#lang s-exp "typecheck.rkt"
(reuse List cons nil #:from "stlc+cons.rkt")
(reuse #:from "stlc+rec-iso.rkt") ; load current-type=?
(extends "stlc+sub.rkt" #:except #%datum #:rename [#%app stlc:#%app])
(reuse #:from "stlc+rec-iso.rkt") ; to load current-type=?
(extends "stlc+sub.rkt" #:except #%datum)
;; Apparently cannot propogate type information across statements.
;; Until the first-class ones work, let's do the big dumb parameter
;; So here's what going to happen
;; - current-Σ will be a map from identifiers to resolvers
;; - resolvers will map overloaded signatures and types to concrete instances
;; - extending a resolver (via instance) will add a new (τ, e) pair to a mutable list
;; Revision of overloading, using identifier macros instead of overriding #%app
;; =============================================================================
@ -30,7 +24,8 @@
name ;; Symbol
dom* ;; (Box (Listof (Pairof Type Expr)))
cod ;; Type
) #:transparent
) #:constructor-name make-
#:transparent
#:property prop:procedure
(lambda (self τ-or-e #:exact? [exact? #f])
(define r
@ -49,10 +44,10 @@
(set-box! dom* (cons (cons τ e) (unbox dom*))))
(define (-init name τ-cod)
( name (box '()) τ-cod))
(make- name (box '()) τ-cod))
(define (->type )
((current-type-eval) #`( #,(assign-type #''α #'#%type) #,(-cod ))))
(define (->type #:subst [τ-dom (assign-type #''α #'#%type)])
((current-type-eval) #`( #,τ-dom #,(-cod ))))
(define (-find τ #:=? =?)
(define (τ=? τ2)
@ -74,72 +69,75 @@
(define (-unbound? τ)
(not (-resolve-syntax τ #:exact? #t)))
(define (syntax-> id)
;; Don't care about the type
(define stx+τ (infer+erase id))
;; Boy, I wish I had a monad
(define (fail)
(error 'resolve (format "Identifier '~a' is not overloaded" (syntax->datum id))))
(unless (pair? stx+τ) (fail))
(define stx (car stx+τ))
(unless (syntax? stx) (fail))
(define -stx (syntax->datum (car stx+τ)))
(unless (and (list? -stx)
(not (null? -stx))
(not (null? (cdr -stx))))
(fail))
(define (cadr -stx))
(unless (? ) (fail))
)
(define-syntax-rule (error-template sym id τ reason)
(error sym (format "Failure for '~a' at type '~a'. ~a"
(syntax->datum id)
(syntax->datum τ)
reason)))
(define-syntax-rule (instance-error id τ reason)
(error-template 'instance id τ reason))
(define-syntax-rule (resolve-error id τ reason)
(error-template 'resolve id τ reason))
)
;; =============================================================================
;; === Overloaded signature environment
(begin-for-syntax
(define current-Σ (make-parameter (lambda (id) #f)))
)
(define-typed-syntax signature
[(_ (name:id α:id) τ)
#:with ((α+) (~→ τ_α:id τ-cod) _) (infer/tyctx+erase #'([α : #%type]) #'τ)
(let ([-old ((current-Σ) #'name)])
(when -old
(error 'signature (format "Identifier '~a' already bound to a type ~a"
(syntax->datum #'name) (syntax->datum (->type -old))))))
(define (-init #'name #'τ-cod))
(current-Σ
(let ([old-Σ (current-Σ)])
(lambda (id)
(if (free-identifier=? id #'name)
(old-Σ id)))))
( (define name #,)
( (define-syntax name
(syntax-parser
[_:id
#'(quote #,)] ;; Is there a way to transmit directly?
[(n e)
#:with [e+ τ+] (infer+erase #'e)
#:with n+ (#, #'τ+)
( (#%app n+ e+)
: τ-cod)]
[(_ e* (... ...))
#'(raise-arity-error (syntax->datum name) 1 e* (... ...))]))
: Bot)]
[(_ e* ...)
(error 'signature (format "Expected (signature (NAME VAR) (→ VAR τ)), got ~a" (xerox #'(e* ...))))])
(define-for-syntax (resolve/internal id τ #:exact? [exact? #f])
(define ((current-Σ) id))
(unless (error 'resolve (format "Identifier '~a' is not overloaded" (syntax->datum id))))
( τ #:exact? exact?))
(define-typed-syntax resolve/tc #:export-as resolve
[(_ name:id τ)
#:with [name+ τ_fn+] (infer+erase #'name)
#:with τ+ ((current-type-eval) #'τ)
(resolve/internal #'name+ #'τ+ #:exact? #t)])
(define-typed-syntax app/tc #:export-as #%app
[(_ e_fn:id e_arg)
#:with [e_fn+ τ_fn+] (infer+erase #'e_fn)
#:when ((current-Σ) #'e_fn+)
#:with [e_arg+ τ_arg+] (infer+erase #'e_arg)
(unless (syntax-e #'τ_arg+)
(error '#%app "(does this ever happen?) No type for expression ~a\n" (syntax->datum #'e_arg)))
(define fn (resolve/internal #'e_fn+ #'τ_arg+))
#`(app/tc #,fn e_arg+)]
[(_ e* ...)
#'(stlc:#%app e* ...)])
(begin-for-syntax
(define-syntax-rule (instance-error id τ r)
(error 'instance (format "Cannot make instance for '~a' at type '~a'. ~a"
(syntax->datum id) (syntax->datum τ) r)))
)
;; Extract a resolver from the syntax object
(define (syntax-> #'name))
;; Apply the resolver to the argument type. woo-wee!
( #,( #'τ+ #:exact? #t) : #,(->type #:subst #'τ+))])
(define-typed-syntax instance
[(_ (name:id τ-stx) e)
#:with τ ((current-type-eval) #'τ-stx)
#:with [e+ τ+] (infer+erase #'e)
(define ((current-Σ) #'name))
(unless (instance-error #'name #'τ "Not an overloaded identifier."))
(define (syntax-> #'name))
(unless (-unbound? #'τ) (instance-error #'name #'τ "Overlaps with existing instance."))
(define does-this-id-matter?
(define _unify ;; Should be a helper function
(syntax-parse #`(τ+ #,(->type ))
[((~→ τ_dom1 τ_cod1)
(~→ _ τ_cod2))
@ -157,8 +155,8 @@
(instance-error #'name #'τ (format "May only overload single-argument functions. (Got ~a and ~a)"
(syntax->datum #'a) (syntax->datum #'b))
)]))
(-add! #'τ #'e+)
;; Should we use syntax instead of e+ ?
(-add! #'τ #'e+)
( (void) : Bot)]
[_
(error 'instance "Expected (instance (id τ) e).")])

View File

@ -1,4 +1,4 @@
#lang s-exp "../stlc+overloading-param.rkt"
#lang s-exp "../stlc+overloading.rkt"
(require "rackunit-typechecking.rkt")
;; -----------------------------------------------------------------------------
@ -104,7 +104,7 @@
(λ ([x : ( Int Int)])
(instance (x Int)
0))
#:with-msg "Not an overloaded identifier")
#:with-msg "Identifier 'x' is not overloaded")
;; -- explicit resolve