add define-primop
This commit is contained in:
parent
e47fb07aba
commit
ee413b96a2
|
@ -2,13 +2,12 @@
|
|||
(require
|
||||
(for-syntax racket/base syntax/parse)
|
||||
"typecheck.rkt")
|
||||
(require (prefix-in stlc: "stlc.rkt"))
|
||||
(require (prefix-in stlc: (only-in "stlc.rkt" #%app λ))
|
||||
(except-in "stlc.rkt" #%app λ))
|
||||
(provide (rename-out [datum/tc #%datum]
|
||||
[stlc:#%app #%app]
|
||||
[stlc:λ λ]))
|
||||
(provide Int
|
||||
(rename-out [stlc:→ →]))
|
||||
(provide #%module-begin #%top-interaction #%top require)
|
||||
(provide (all-from-out "stlc.rkt"))
|
||||
|
||||
;; Simply-Typed Lambda Calculus, plus numeric literals and primitives
|
||||
;; forms from stlc.rkt
|
||||
|
@ -17,6 +16,8 @@
|
|||
|
||||
(define-base-type Int)
|
||||
|
||||
(define-primop + : (Int Int → Int))
|
||||
|
||||
(define-syntax (datum/tc stx)
|
||||
(syntax-parse stx
|
||||
[(_ . n:integer) (⊢ (syntax/loc stx (#%datum . n)) #'Int)]
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
#lang racket/base
|
||||
(require
|
||||
(for-syntax racket/base syntax/parse syntax/stx "stx-utils.rkt")
|
||||
(for-syntax racket/base syntax/parse syntax/stx racket/string "stx-utils.rkt")
|
||||
"typecheck.rkt")
|
||||
(provide (rename-out [λ/tc λ] [app/tc #%app])
|
||||
→)
|
||||
(provide (rename-out [λ/tc λ] [app/tc #%app]))
|
||||
(provide #%module-begin #%top-interaction #%top require)
|
||||
|
||||
;; Simply-Typed Lambda Calculus
|
||||
|
@ -22,13 +21,26 @@
|
|||
(define-syntax (app/tc stx)
|
||||
(syntax-parse stx #:literals (→)
|
||||
[(_ e_fn e_arg ...)
|
||||
#:with (e_fn- (τ ... → τ_res)) (infer+erase #'e_fn)
|
||||
#:with (e_fn- τ_fn) (infer+erase #'e_fn)
|
||||
#:fail-unless (→? #'τ_fn)
|
||||
(format "Type error: Attempting to apply a non-function ~a with type ~a\n"
|
||||
(syntax->datum #'e_fn) (syntax->datum #'τ_fn))
|
||||
#:with (τ ... → τ_res) #'τ_fn
|
||||
#:with ((e_arg- τ_arg) ...) (infers+erase #'(e_arg ...))
|
||||
#:fail-unless (= (stx-length #'(τ ...))
|
||||
(stx-length #'(τ_arg ...)))
|
||||
(format "Wrong number of arguments: given ~a, expected ~a\n"
|
||||
(stx-length #'(τ_arg ...)) (stx-length #'(τ ...)))
|
||||
; #:fail-unless (= (stx-length #'(τ ...))
|
||||
; (stx-length #'(τ_arg ...)))
|
||||
; (format "Wrong number of arguments: given ~a, expected ~a\n"
|
||||
; (stx-length #'(τ_arg ...)) (stx-length #'(τ ...)))
|
||||
#:fail-unless (types=? #'(τ ...) #'(τ_arg ...))
|
||||
(format "Arguments have wrong type: given ~a, expected ~a\n"
|
||||
(syntax->datum #'(τ_arg ...)) (syntax->datum #'(τ ...)))
|
||||
(string-append
|
||||
(format
|
||||
"Wrong number of args given to function ~a, or args have wrong type:\ngiven: "
|
||||
(syntax->datum #'e_fn))
|
||||
(string-join
|
||||
(map (λ (e+τ) (format "~a : ~a" (car e+τ) (cadr e+τ))) (syntax->datum #'([e_arg τ_arg] ...)))
|
||||
", ")
|
||||
"\nexpect arguments with type: "
|
||||
(string-join
|
||||
(map (λ (x) (format "~a" x)) (syntax->datum #'(τ ...)))
|
||||
", "))
|
||||
(⊢ #'(#%app e_fn- e_arg- ...) #'τ_res)]))
|
||||
|
|
|
@ -11,4 +11,11 @@
|
|||
(check-type (λ ([f : (Int → Int)]) 1) : ((Int → Int) → Int))
|
||||
(check-type ((λ ([x : Int]) x) 1) : Int ⇒ 1)
|
||||
;((λ ([x : Bool]) x) 1)
|
||||
;(λ ([x : Bool]) x)
|
||||
;(λ ([x : Bool]) x)
|
||||
(typecheck-fail (λ ([f : Int]) (f 1 2)))
|
||||
(check-type (λ ([f : (Int Int → Int)] [x : Int] [y : Int]) (f x y))
|
||||
: ((Int Int → Int) Int Int → Int))
|
||||
(check-type ((λ ([f : (Int Int → Int)] [x : Int] [y : Int]) (f x y)) + 1 2) : Int ⇒ 3)
|
||||
(typecheck-fail (+ 1 (λ ([x : Int]) x)))
|
||||
(typecheck-fail (λ ([x : (Int → Int)]) (+ x x)))
|
||||
(check-type ((λ ([x : Int]) (+ x x)) 10) : Int ⇒ 20)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#lang racket/base
|
||||
(require
|
||||
(for-syntax racket/base syntax/parse racket/list syntax/stx "stx-utils.rkt")
|
||||
(for-syntax racket/base syntax/parse racket/list racket/syntax syntax/stx "stx-utils.rkt")
|
||||
(for-meta 2 racket/base syntax/parse racket/list syntax/stx "stx-utils.rkt"))
|
||||
(provide
|
||||
(for-syntax (all-defined-out))
|
||||
|
@ -23,15 +23,27 @@
|
|||
(define-syntax (define-base-type stx)
|
||||
(syntax-parse stx
|
||||
[(_ τ:id)
|
||||
#'(define-syntax (τ stx)
|
||||
(syntax-parse stx
|
||||
[_ (error 'Int "Cannot use type at run time.")]))]))
|
||||
#'(begin
|
||||
(provide τ)
|
||||
(define-syntax (τ stx)
|
||||
(syntax-parse stx
|
||||
[_ (error 'Int "Cannot use type at run time.")])))]))
|
||||
(define-syntax (define-type-constructor stx)
|
||||
(syntax-parse stx
|
||||
[(_ τ:id)
|
||||
#'(define-syntax (τ stx)
|
||||
(syntax-parse stx
|
||||
[_ (error 'Int "Cannot use type at run time.")]))]))
|
||||
#:with τ? (format-id #'τ "~a?" #'τ)
|
||||
#'(begin
|
||||
(provide τ)
|
||||
(define-syntax (τ stx)
|
||||
(syntax-parse stx
|
||||
[_ (error 'Int "Cannot use type at run time.")]))
|
||||
(define-for-syntax (τ? stx)
|
||||
(syntax-parse stx
|
||||
[(τ_arg (... ...))
|
||||
(for/or ([id (syntax->list #'(τ_arg (... ...)))])
|
||||
(type=? #'τ id))]
|
||||
[_ #f]))
|
||||
)]))
|
||||
|
||||
;; type classes
|
||||
(begin-for-syntax
|
||||
|
@ -56,21 +68,21 @@
|
|||
[(b:typed-binding ...)
|
||||
#:with (x ...) #'(b.x ...)
|
||||
#:with (τ ...) #'(b.τ ...)
|
||||
; #:with arr (datum->syntax e '→)
|
||||
#:with
|
||||
(lam xs+ (lr-stxs+vs1 stxs1 vs1 (lr-stxs+vs2 stxs2 vs2 e+)))
|
||||
(expand/df
|
||||
#`(λ (x ...)
|
||||
(let-syntax ([x (make-rename-transformer (⊢ #'x #'τ))] ...) #,e)))
|
||||
; (list #'(lam xs+ e+) #`(τ ... arr #,(typeof #'e+)))]))
|
||||
(list #'xs+ #'e+ (typeof #'e+))]))
|
||||
|
||||
(define (infer+erase e)
|
||||
(define e+ (expand/df e))
|
||||
(list e+ (typeof e+)))
|
||||
(define (infers+erase es) (stx-map infer+erase es))
|
||||
(define (infers+erase es)
|
||||
(stx-map infer+erase es))
|
||||
(define (types=? τs1 τs2)
|
||||
(stx-andmap type=? τs1 τs2))
|
||||
(and (= (stx-length τs1) (stx-length τs2))
|
||||
(stx-andmap type=? τs1 τs2)))
|
||||
|
||||
;; typeof : Syntax -> Type or #f
|
||||
;; Retrieves type of given stx, or #f if input has not been assigned a type.
|
||||
|
@ -81,14 +93,14 @@
|
|||
|
||||
;; assert-type : Syntax Type -> Boolean
|
||||
;; Returns #t if (typeof e)==τ, else type error
|
||||
(define (assert-type e τ)
|
||||
#;(define (assert-type e τ)
|
||||
; (printf "~a has type " (syntax->datum e))
|
||||
; (printf "~a; expected: " (syntax->datum (typeof e)))
|
||||
; (printf "~a\n" (syntax->datum τ))
|
||||
(or (type=? (typeof e) τ)
|
||||
(type-error #:src e
|
||||
#:msg "~a has type ~a, but should have type ~a" e (typeof e) τ)))
|
||||
(define (assert-types es τs)
|
||||
#;(define (assert-types es τs)
|
||||
(stx-andmap assert-type es τs))
|
||||
|
||||
;; type=? : Type Type -> Boolean
|
||||
|
@ -97,9 +109,11 @@
|
|||
(syntax-parse #`(#,τ1 #,τ2)
|
||||
; → should not be datum literal;
|
||||
; adding a type constructor should extend type equality
|
||||
#:datum-literals (→)
|
||||
; #:datum-literals (→)
|
||||
[(x:id y:id) (free-identifier=? τ1 τ2)]
|
||||
[((x ... → x_out) (y ... → y_out))
|
||||
[((τ1 ...) (τ2 ...))
|
||||
(types=? #'(τ1 ...) #'(τ2 ...))]
|
||||
#;[((x ... → x_out) (y ... → y_out))
|
||||
(and (type=? #'x_out #'y_out)
|
||||
(stx-andmap type=? #'(x ...) #'(y ...)))]
|
||||
[_ #f]))
|
||||
|
@ -134,10 +148,47 @@
|
|||
'TYPE-ERROR
|
||||
(format (string-append "~a (~a:~a): " msg)
|
||||
(syntax-source stx-src) (syntax-line stx-src) (syntax-column stx-src)
|
||||
(syntax->datum args) ...))))
|
||||
(syntax->datum args) ...)))
|
||||
|
||||
)
|
||||
|
||||
(define-syntax (define-primop stx)
|
||||
(syntax-parse stx #:datum-literals (:)
|
||||
[(_ op:id : τ)
|
||||
#:with op/tc (generate-temporary #'op)
|
||||
#`(begin
|
||||
(provide (rename-out [op/tc op]))
|
||||
(define-syntax (op/tc stx)
|
||||
(syntax-parse stx
|
||||
[f:id (⊢ (syntax/loc stx op) #'τ)] ; HO case
|
||||
[(_ x (... ...))
|
||||
#:with app (datum->syntax stx '#%app)
|
||||
#:with op (format-id stx "~a" #'op)
|
||||
#'(app op x (... ...))]
|
||||
#;[(_ e (... ...))
|
||||
#:with es+ (stx-map expand/df #'(e (... ...)))
|
||||
#:with τs #'(τ_arg ...)
|
||||
#:fail-unless (let ([es-len (stx-length #'es+)]
|
||||
[τs-len (stx-length #'τs)])
|
||||
(or (and #,(if (attribute ldots) #t #f)
|
||||
(>= (- es-len (sub1 τs-len)) 0))
|
||||
(= es-len τs-len)))
|
||||
#,(if (attribute ldots)
|
||||
#'(format "Wrong number of arguments, given ~a, expected at least ~a"
|
||||
(stx-length #'es+) (sub1 (stx-length #'τs)))
|
||||
#'(format "Wrong number of arguments, given ~a, expected ~a"
|
||||
(stx-length #'es+) (stx-length #'τs)))
|
||||
#:with τs-ext #,(if (attribute ldots)
|
||||
#'(let* ([diff (- (stx-length #'es+) (sub1 (stx-length #'τs)))]
|
||||
[last-τ (stx-last #'τs)]
|
||||
[last-τs (build-list diff (λ _ last-τ))])
|
||||
(append (drop-right (syntax->list #'τs) 1) last-τs))
|
||||
#'#'τs)
|
||||
#:when (stx-andmap assert-type #'es+ #'τs-ext)
|
||||
(⊢ (syntax/loc stx (op . es+)) #'τ_result)])))]))
|
||||
|
||||
;; type environment -----------------------------------------------------------
|
||||
(begin-for-syntax
|
||||
#;(begin-for-syntax
|
||||
|
||||
;; A Variable is a Symbol
|
||||
;; A TypeEnv is a [HashOf Variable => Type]
|
||||
|
|
Loading…
Reference in New Issue
Block a user