Work in progress for implementing (structure) so that it is both a hybrid function and empty struct, but actually it can't be passed to polymorphic functions (like map, …), so it's probably better to just add an optional #:instance or #:constructor argument to clarify.

This commit is contained in:
Georges Dupéron 2015-12-10 17:19:11 +01:00
parent 8a398ae5a3
commit 9de841d95f
6 changed files with 385 additions and 44 deletions

View File

@ -1,5 +1,19 @@
#lang debug typed/racket
(require "structure.lp2.rkt")
(require "../type-expander/type-expander.lp2.rkt")
(require "../lib/low.rkt")
(define-structure st [a Number] [b String])
(check-equal:? (st 1 "b") (structure [a 1] [b "b"]))
(check-equal:? (st 1 "b") (structure [a : Number 1] [b : String "b"]))
(check-equal:? (st 1 "b") ((structure [a : Number] [b : String]) 1 "b"))
(check-equal:? (st 1 "b") ((structure [a] [b]) 1 "b"))
(check-equal:? (st 1 "b") ((structure a b) 1 "b"))
(check-equal:? (st 1 "b") ((structure [a] b) 1 "b"))
#|
(require (submod "graph3.lp2.rkt" test))
(require "../lib/low.rkt")
(require racket/list)
@ -34,3 +48,5 @@
x))
(forceall 5 g)
|#

View File

@ -38,3 +38,5 @@
(structure faa fab fav)
(structure fba fbv)
(structure fav)
(structure a)
(structure a)

View File

@ -12,12 +12,116 @@ Structures are represented using regular racket @tc[struct]s, see
@seclink["type-system|structures"]{the overview document}.
@;secref["structures" #:doc "type-system.scrbl"].
When called, @tc[structure] accepts several syntaxes:
@tc[(structure [field] )], which returns a constructor with @tc[] types for,
@tc[(structure [field value] )], which returns an instance, inferring the type
of the fields, @tc[(structure [field : type] )], which returns a constructor
with the given types, or @tc[(structure [field : type value] )], which returns
an instance using the given types. the types have to be all provided, or not
given at all, but a mix of typed and @tc[] is not allowed for now (rationale:
since typed/racket currently doesn't support named instantiation of polymorphic
types, it wouldn't be clear what fields the remaining type parameters affect).
@;{(begin-for-syntax
(define-syntax-class field-descriptor
(pattern
(~or field:id
[field:id (~maybe (~lit :) type:expr) (~maybe value:expr)]))))}
@chunk[<structure>
(define-multi-id structure
#:type-expander structure-type-expander
#:match-expander structure-match-expander
#:call (λ/syntax-parse (_ [field value] ...)
#'((make-structure-constructor field ...) value ...)))]
#:call (λ (stx)
(syntax-parse stx
[(_) <hybrid-empty>]
[(_ (~or (~seq (~or-bug [field:id] field:id) )
(~seq [field:id (~lit :) type:expr] )
(~seq [field:id value:expr] )
(~seq [field:id (~lit :) type:expr value:expr] )))
(define/with-syntax c
#'(make-structure-constructor field ))
(define/with-syntax ct
(if (and (attribute type) (not (stx-null? #'(type ))))
#'(inst c type )
#'c))
(template (?? (ct value ) ct))])))]
@subsection[#:tag "structure|hybrid-empty"]{Hybrid constructor / instance for
the empty structure}
A call to @tc[(structure)] with no field, is ambiguous: it could return a
constructor function, or an instance. We use @tc[define-struct/exec] to make it
behave like both.
@CHUNK[<declare-hybrid-empty>
(struct empty/noexec-type ())
(define-struct/exec (empty/exec-type empty)
()
[(λ _ empty-instance) : ( Any empty)])
(define empty-instance (empty/exec-type))]
@CHUNK[<test-hybrid-empty>
(check-equal:? empty-instance : empty empty-instance)
(check-equal:? empty-instance : empty (empty-instance))
(check-equal:? (empty-instance) : empty empty-instance)
(check-equal:? (empty-instance) : empty (empty-instance))]
@CHUNK[<test-hybrid-empty-2>
(check-equal:? (structure) (structure))
(check-equal:? (structure) ((structure)))
(check-equal:? ((structure)) (structure))
(check-equal:? ((structure)) ((structure)))]
@chunk[<test-structure>
(let ()
(define-structure empty-st)
(define-structure stA [a Number])
(check-equal:? (empty-st) ((structure)))
(check-not-equal:? (empty-st) (structure [a 1]))
(check-not-equal:? (structure) (structure [a 1]))
(check-not-equal:? (empty-st) (stA 1))
(check-not-equal:? (structure) (stA 1)))
#;(let ()
(define-structure st [a Number] [b String])
(define-structure stA [a Number])
(define-structure stABC [a Number] [b String] [c Number])
(define st1 (st 1 "b"))
(check-equal:? st1 (structure [a 1] [b "b"]))
(check-equal:? st1 (structure [a : Number 1] [b : String "b"]))
(check-equal:? st1 ((structure [a : Number] [b : String]) 1 "b"))
(check-equal:? st1 ((structure [a] [b]) 1 "b"))
(check-equal:? st1 ((structure a b) 1 "b"))
(check-equal:? st1 ((structure [a] b) 1 "b"))
(define st2 (st 2 "b"))
(check-not-equal:? st2 st1)
(check-not-equal:? st2 (structure [a 1] [b "b"]))
(check-not-equal:? st2 (structure [a : Number 1] [b : String "b"]))
(check-not-equal:? st2 ((structure [a : Number] [b : String]) 1 "b"))
(check-not-equal:? st2 ((structure [a] [b]) 1 "b"))
(check-not-equal:? st2 ((structure a b) 1 "b"))
(check-not-equal:? st2 ((structure [a] b) 1 "b"))
(define sta (stA 1))
(check-not-equal:? sta st1)
(check-not-equal:? sta (structure [a 1] [b "b"]))
(check-not-equal:? sta (structure [a : Number 1] [b : String "b"]))
(check-not-equal:? sta ((structure [a : Number] [b : String]) 1 "b"))
(check-not-equal:? sta ((structure [a] [b]) 1 "b"))
(check-not-equal:? sta ((structure a b) 1 "b"))
(check-not-equal:? sta ((structure [a] b) 1 "b"))
(define st3 (stABC 1 "b" 3))
(check-not-equal:? st3 st1)
(check-not-equal:? st3 (structure [a 1] [b "b"]))
(check-not-equal:? st3 (structure [a : Number 1] [b : String "b"]))
(check-not-equal:? st3 ((structure [a : Number] [b : String]) 1 "b"))
(check-not-equal:? st3 ((structure [a] [b]) 1 "b"))
(check-not-equal:? st3 ((structure a b) 1 "b"))
(check-not-equal:? st3 ((structure [a] b) 1 "b")))]
@chunk[<define-structure>
(define-syntax (define-structure stx)
@ -34,16 +138,20 @@ Structures are represented using regular racket @tc[struct]s, see
(syntax-case stx2 ()
[(_ pat ...) #'(structure [field pat] ...)]))
#:else
(inst (make-structure-constructor field ...) type ...))]))]
(if (not (stx-null? #'(type )))
#'(inst (make-structure-constructor field ...) type ...)
#'(make-structure-constructor field ...)))]))]
@chunk[<test-define-structure>
(define-structure empty-st)
(define-structure st [a Number] [b String])
(define-structure st2 [b String] [a Number])]
Test constructor:
@chunk[<test-define-structure>
(check-equal:? (empty-st) : empty-st (empty-st))
(check-equal:? (get (st 1 "b") b) : String "b")
(check-equal:? (get (st2 "a" 2) b) : String "a")]
@ -139,10 +247,18 @@ one low-level @tc[struct] is generated for them.
@CHUNK[<named-sorted-structures>
(define-for-syntax named-sorted-structures
(for/list ([s (remove-duplicates (map (λ (s) (sort s symbol<?))
(get-remembered 'structure)))]
<all-remembered-structs+empty>))]
[i (in-naturals)])
`(,(string->symbol (format "struct-~a" i)) . ,s)))]
We add the empty struct (with no fields) to the list of remembered structs as a
special case, because we need it to define the hybrid instance/constructor in
section @secref{structure|hybrid-empty}.
@chunk[<all-remembered-structs+empty>
(cons '()
(get-remembered 'structure))]
We will also need utility functions to sort the fields when querying this
associative list.
@ -175,8 +291,8 @@ be used to make @tc[structure] instances like this:
@chunk[<test-make-structure-constructor>
(check-equal? (begin ((make-structure-constructor a b c) 1 "b" #t)
#t)
#t)]
'it-works)
'it-works)]
To create such an instance, we use the underlying @tc[struct]'s constructor.
First, we need to check if the list of fields was already remembered, in which
@ -332,8 +448,8 @@ instead of needing an extra recompilation.
(let ()
(define/with-syntax ([sorted-field sorted-type] ...)
(sort-car-fields #'((field type) ...)))
(if (null? (syntax->list #'(sorted-type ...)))
(fields→stx-name #'(field ...))
(if (stx-null? #'(sorted-type ...))
(fields→stx-name #'(field )) ; #'(field …) is empty here.
#`(#,(fields→stx-name #'(field ...)) sorted-type ...)))
(remember-all-errors #'U stx #'(field ...)))]))]
@ -417,6 +533,7 @@ chances that we could write a definition for that identifier.
(require (for-syntax racket
racket/syntax
syntax/parse
syntax/parse/experimental/template
mzlib/etc
racket/struct-info
syntax/stx
@ -441,6 +558,9 @@ chances that we could write a definition for that identifier.
<sort-fields>
<declare-all-structs>
<fields→stx-name>
<declare-hybrid-empty>
(require typed/rackunit)
<test-hybrid-empty>
<make-structure-constructor>
<delayed-error-please-recompile>
@ -468,7 +588,9 @@ chances that we could write a definition for that identifier.
<test-get-field>
<test-match-expander>
<test-type-expander>
<test-structure>
<test-define-structure>
<test-hybrid-empty-2>
(require (submod ".." doc))))]

View File

@ -91,12 +91,51 @@
(require 'mb)
(check-equal? require-provide-foo 7))
;; ==== low/define-syntax-parse.rkt ====
;; ==== low/syntax-parse.rkt ====
(require syntax/parse
syntax/parse/define)
syntax/parse/define
(for-syntax racket/syntax))
(provide define-syntax/parse
λ/syntax-parse)
λ/syntax-parse
~maybe
~lit
~or-bug)
(define-syntax ~maybe
(pattern-expander
(λ (stx)
(syntax-case stx ()
[(~maybe pat ...)
(datum->syntax #'~maybe
#'(~optional (~seq pat ...)))]))))
;; Circumvent the bug that causes "syntax-parse: duplicate attribute in: a" in:
;; (syntax-parse #'(x y z) [((~or a (a b c)) ...) #'(a ...)])
(define-syntax ~or-bug
(pattern-expander
(λ (stx)
(syntax-case stx ()
[(~or-bug pat ...)
(let ()
(define (s stx) (datum->syntax #'~or-bug stx))
;(define/with-syntax ~~and (datum->syntax #'~or-bug #'~and))
;(define/with-syntax ~~parse (datum->syntax #'~or-bug #'~parse))
;(define/with-syntax ~~or (datum->syntax #'~or-bug #'~parse))
#;#'(~~and x (~~parse (~~or pat ...) #'x))
#`(#,(s #'~and) x (#,(s #'~parse) #,(s #'(~or pat ...)) #'x))
)]))))
(define-syntax ~lit
(pattern-expander
(λ (stx)
(syntax-case stx ()
[(~lit lit)
(datum->syntax #'~lit
#'(~literal lit))]
[(~lit lit )
(datum->syntax #'lit
#'(~seq (~literal lit)))]))))
(begin-for-syntax
(require (for-syntax racket/base
@ -132,7 +171,8 @@
syntax/parse/experimental/template)
typed/rackunit)
(provide check-equal:?)
(provide check-equal:?
check-not-equal:?)
;; TODO: this won't expand types in the ann.
@ -140,7 +180,15 @@
(check-equal:? actual
(~optional (~seq (~datum :) type))
expected)
(template (check-equal? (?? (ann actual type) actual) expected)))
(template (check-equal? (?? (ann actual type) actual)
(?? (ann expected type) expected))))
(define-syntax/parse
(check-not-equal:? actual
(~optional (~seq (~datum :) type))
expected)
(template (check-not-equal? (?? (ann actual type) actual)
(?? (ann expected type) expected))))
;; ==== low/typed-fixnum.rkt ===
@ -637,14 +685,14 @@
(define/with-syntax pat
(format-id #'base.id (syntax-e #'format) #'base.id))
(define/with-syntax pat-dotted ((attribute base.make-dotted) #'pat))
(define/with-syntax format-temp-ids*
((attribute base.wrap) #'(compose car (curry format-temp-ids format))
(λ (x deepest?)
(if deepest?
x
#`(curry stx-map #,x)))))
(syntax-cons-property
(template (begin (define/with-syntax pat-dotted
(format-temp-ids* #'base))

View File

@ -14,16 +14,21 @@ TODO: maybe we should cache @tc[p-else] and @tc[p-get].
'self
(format "can't set ~a" (syntax->datum #'self)))]
@chunk[<stx-class-kw-else>
@CHUNK[<stx-class-kw-else>
(define-splicing-syntax-class kw-else
#:attributes (p-just-set! p-just-call p-just-id)
(pattern (~seq #:mutable-else p-else)
#:with p-just-set! #'#'(set! p-else . rest)
#:with p-just-call #'#'(p-else . rest)
#:with p-just-id #'#'p-else)
(pattern (~seq #:else p-else)
#:with p-just-set! <fail-set!>
#:with p-just-call #'#'(p-else . rest)
#:with p-just-id #'#'p-else))]
#:with p-just-call #'#`(#,p-else . rest)
#:with p-just-id #'p-else)
(pattern (~seq #:mutable-else-id p-else-id)
#:with (:kw-else) #'(#:mutable-else #'p-else-id))
(pattern (~seq #:else-id p-else-id)
#:with (:kw-else) #'(#:else #'p-else-id)))]
@chunk[<stx-class-kw-set!+call+id>
(define-splicing-syntax-class kw-set!+call+id
@ -31,6 +36,10 @@ TODO: maybe we should cache @tc[p-else] and @tc[p-get].
(~optional (~or (~seq #:call p-user-call:expr)
(~seq #:call-id p-user-call-id:id)))
(~optional (~seq #:id p-user-id:expr)))
; TODO: add #:macro with prop:procedure, see
; file:///usr/local/racket-6.3.0.4/doc/syntax/stxparse-patter
; ns.html?q=~optional#%28def._%28%28lib._syntax%2Fparse..rkt%
; 29._prop~3apattern-expander%29%29
#:attr p-just-set!
(and (attribute p-user-set!) #'(p-user-set! stx))
#:attr p-just-call
@ -129,6 +138,31 @@ to configure).
Test with @tc[#:else]:
@chunk[<test-multi-id>
(define-multi-id bar-id
#:type-expander
(λ (stx) #'(List `,(Repeat 'x 2) Number))
#:match-expander
(λ (stx) #'(cons _ _))
#:custom-write
(λ (self port mode) (display "custom-write for foo" port))
#:else-id p1)
(check-equal? (ann (ann '((x x) 79) bar)
(List (List 'x 'x) Number))
'((x x) 79))
;(set! bar 'bad)
(let ([test-match (λ (val) (match val [(bar-id) #t] [_ #f]))])
(check-equal? (test-match '(a . b)) #t)
(check-equal? (test-match #(1 2 3)) #f))
(let ([f-bar-id bar-id])
(check-equal? (f-bar-id 6) 7))
(check-equal? (bar-id 6) 7)
(check-equal? (map bar-id '(1 5 3 4 2)) '(2 6 4 5 3))]
@chunk[<test-multi-id>
(define-multi-id bar
#:type-expander
@ -137,7 +171,7 @@ Test with @tc[#:else]:
(λ (stx) #'(cons _ _))
#:custom-write
(λ (self port mode) (display "custom-write for foo" port))
#:else p1)
#:else #'p1)
(check-equal? (ann (ann '((x x) 79) bar)
(List (List 'x 'x) Number))

View File

@ -40,9 +40,9 @@ contain the expander procedure, or directly an expander procedure.
[else
(raise-argument-error
'prop:type-expander-guard
(~a "an exact non-negative integer designating a field index "
"within the structure that should contain a procedure of "
"arity 1, or a procedure of arity 1.")
(~a "a procedure of arity 1, or an exact non-negative integer "
"designating a field index within the structure that "
"should contain a procedure of arity 1.")
val)]))]
If the value is a field index, it should be within bounds. The
@ -269,7 +269,7 @@ ususal @code{#'()} and @code{#`()}. In order to expand types and bind type
variables in the result, we define two template metafunctions:
@chunk[<template-metafunctions>
(define-template-metafunction (template-expand-type stx)
(define-template-metafunction (tmpl-expand-type stx)
(syntax-parse stx
[(_ () t) (expand-type #'t)]
[(_ tvars t) (expand-type (bind-type-vars #'tvars #'t))]))]
@ -329,7 +329,7 @@ them.
(~optional default:expr)])
#:with tvars tvars
#:with (expanded ...)
(template (kw [id (?@ : (template-expand-type tvars type))
(template (kw [id (?@ : (tmpl-expand-type tvars type))
(?? default)]))))
(define-splicing-syntax-class (new-mand-formal tvars)
@ -339,7 +339,7 @@ them.
(pattern [id:id :colon type:expr]
#:with tvars tvars
#:with (expanded ...)
(template ([id : (template-expand-type tvars type)])))
(template ([id : (tmpl-expand-type tvars type)])))
(pattern (~var kw (new-kw-formal tvars))
#:with (expanded ...) #'(kw.expanded ...)))
@ -348,7 +348,7 @@ them.
(pattern [id:id (~optional (~seq :colon type:expr)) default:expr]
#:with tvars tvars
#:with (expanded ...)
(template ([id (?@ : (template-expand-type tvars type))
(template ([id (?@ : (tmpl-expand-type tvars type))
default])))
(pattern (~var kw (new-kw-formal tvars))
#:with (expanded ...) #'(kw.expanded ...)))
@ -363,8 +363,8 @@ them.
(~seq (~datum ...) bound:expr)))
#:with tvars tvars
#:with expanded
(template (rest : (template-expand-type tvars type)
(?? x* (?@ (... ...) (template-expand-type
(template (rest : (tmpl-expand-type tvars type)
(?? x* (?@ (... ...) (tmpl-expand-type
tvars bound)))))))
(define-syntax-class (new-lambda-formals tvars)
@ -394,7 +394,7 @@ them.
#:with tvars tvars
#:with expanded
(template (name
(?? (?@ : (template-expand-type tvars type)))))))
(?? (?@ : (tmpl-expand-type tvars type)))))))
(define-syntax-class (new-name-or-parenthesised-annotated-name tvars)
(pattern name:id
@ -402,7 +402,7 @@ them.
(pattern [id:id :colon type:expr]
#:with tvars tvars
#:with expanded
(template [id : (template-expand-type tvars type)])))]
(template [id : (tmpl-expand-type tvars type)])))]
@subsection{@racket[define-type]}
@ -412,7 +412,7 @@ them.
[(_ (~or name:id (name:id TVar ...)) type . rest)
(template
(define-type (?? (name TVar ...) name)
(template-expand-type (?? (TVar ...) ()) type)
(tmpl-expand-type (?? (TVar ...) ()) type)
. rest))]))]
@chunk[<test-define-type>
@ -437,7 +437,7 @@ them.
e ...)
(template
(define (?@ . tvars) (?? v formals.expanded)
(?? (?@ : (template-expand-type tvars.vars type)))
(?? (?@ : (tmpl-expand-type tvars.vars type)))
e ...))]))]
@CHUNK[<test-define>
@ -471,7 +471,7 @@ them.
(~optional (~seq :colon ret-type))
e ...)
(template (lambda (?@ . tvars) args.expanded
(?? (?@ : (template-expand-type tvars.vars ret-type)))
(?? (?@ : (tmpl-expand-type tvars.vars ret-type)))
e ...))]))]
@CHUNK[<test-lambda>
@ -495,8 +495,12 @@ them.
(~and name+parent (~or name:id [name:id parent:id]))
([field:id :colon type:expr] ...)
. rest)
(template (struct (?? tvars.maybe) name+parent
([field : (template-expand-type tvars.vars type)] ...)
(displayln #'(tvars= tvars
name+parent= name+parent
field...= field ...
rest= rest))
(template (struct (?? tvars.maybe) name (?? parent)
([field : (tmpl-expand-type tvars.vars type)] ...)
. rest))]))]
@chunk[<test-struct>
@ -507,6 +511,11 @@ them.
(struct s4 () #:transparent)
(struct (A B) s5 ([x : A] [y : B]) #:transparent)
(struct (A B) s6 () #:transparent)
(struct (s7 s2) ([z : String]) #:transparent)
(struct (A) (s8 s3) ([z : A]) #:transparent)
(struct (A B C) (s9 s5) ([z : C]) #:transparent)
(struct (A B C) (s10 s2) ([z : C]) #:transparent)
(struct (A B C) (s11 s5) ([z : C]))
(check (λ (a b) (not (equal? a b))) (s0) (s0))
(check-equal? (s1-x (s1 123)) 123)
@ -518,13 +527,119 @@ them.
(check-equal? (s5-x (s5 6 7)) 6)
(check-equal? (s5-y (s5 6 7)) 7)
(check-equal? (s5 6 7) (s5 6 7))
(check-equal? (s6) (s6))]
(check-equal? ((inst s5 Number String) 6 "g") (s5 6 "g"))
(check-equal? (s6) (s6))
(check-equal? ((inst s6 Number String)) (s6))
;(check-equal? (s7-x (s7 -1 -2 "c") -1))
;(check-equal? (s7-y (s7 -1 -2 "c") -2))
(check-equal? (s7-z (s7 -1 -2 "c")) "c")
(check-equal? (s2-x (s7 -1 -2 "c")) -1)
(check-equal? (s2-y (s7 -1 -2 "c")) -2)
(check-not-equal? (s7 -1 -2 "c") (s7 -1 -2 "c"))
(check-not-exn (λ () (ann (s7 -1 -2 "c") s2)))
(check-true (s2? (s7 -1 -2 "c")))
;(check-equal? (s8-x (s8 -1 -2 "c") -1))
;(check-equal? (s8-y (s8 -1 -2 "c") -2))
(check-equal? (s8-z (s8 -1 -2 "c")) "c")
(check-equal? (s3-x (s8 -1 -2 "c")) -1)
(check-equal? (s3-y (s8 -1 -2 "c")) -2)
(check-equal? (s8 -1 -2 "c") (s8 -1 -2 "c"))
(check-equal? ((inst s8 String) -1 -2 "c") (s8 -1 -2 "c"))
(check-not-exn (λ () (ann ((inst s8 String) -1 -2 "c") s3)))
(check-true (s3? ((inst s8 String) -1 -2 "c")))
;(check-equal? (s9-x (s9 8 9 10)) 8)
;(check-equal? (s9-y (s9 8 9 10)) 9)
(check-equal? (s9-z (s9 8 9 10)) 10)
(check-equal? (s5-x (s9 8 9 10)) 8)
(check-equal? (s5-y (s9 8 9 10)) 9)
(check-equal? (s9 8 9 10) (s9 8 9 10))
;(check-not-exn (λ () (ann ((inst s9 Number Symbol String) 8 'i "j");;;;;;;;;;;;;;
; (Struct s5))));;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(check-not-exn (λ () (ann ((inst s9 Number Symbol String) 8 'i "j")
(s5 Number Symbol))))
(check-true (s5? ((inst s9 Number Symbol String) -1 'i "j")))
(check-not-equal? (s10 11 12 13) (s10 11 12 13))
(check-not-equal? (s11 14 15 16) (s11 14 15 16))]
@subsection{@racket[define-struct/exec]}
@chunk[<define-struct/exec>
(define-syntax (new-define-struct/exec stx)
(syntax-parse stx
[(_ (~and name+parent (~or name:id [name:id parent:id]))
([field:id (~maybe :colon type:expr)] ...)
[proc :colon proc-type])
(template (define-struct/exec name+parent
([field (?? (?@ : (tmpl-expand-type () type)))] ...)
[proc : (tmpl-expand-type () proc-type)]))]))]
@chunk[<test-define-struct/exec>
(define-struct/exec se0 ()
;[(λ (self v) (cons self v)) : (∀ (A) (→ se0 A (Pairof se0 A)))])
[(λ (self v) (cons self v)) : ( se0 Any (Pairof se0 Any))])
(define-struct/exec se1 ([x : Number])
;[(λ (self v) (cons self v)) : (∀ (A) (→ se0 A (Pairof se0 A)))])
[(λ (self v) (cons self v)) : ( se1 Any (Pairof se1 Any))])
(define-struct/exec se2 ([x : Number] [y : Number])
[(λ (self v) (cons self v)) : ( se2 Any (Pairof se2 Any))])
(define-struct/exec (se3 se2) ([z : String])
[(λ (self v w) (list self v w))
;: (∀ (A B) (→ se3 A B (List se2 A B)))])
: ( se3 Any Any (List se2 Any Any))])
(define-struct/exec (se4 se2) ([z : String])
[(λ (self v w) (list self v w))
;: (∀ (A B) (→ se4 A B (List se2 A B)))])
: ( se4 Any ( Number Number) (List se2 Any ( Number Number)))])
(check (λ (a b) (not (equal? a b))) (se0) (se0))
(check-equal? (cdr ((se0) 'a)) 'a)
(check-not-exn (λ () (ann (car ((se0) 'a)) se0)))
(check-true (se0? (car ((se0) 'a))))
(check (λ (a b) (not (equal? a b))) (se1 123) (se1 123))
(check-equal? (se1-x (se1 123)) 123)
(check-equal? (se1-x (car ((se1 123) 'b))) 123)
(check-equal? (cdr ((se1 123) 'b)) 'b)
(check-not-exn (λ () (ann (car ((se1 123) 'b)) se1)))
(check-true (se1? (car ((se1 123) 'b))))
(check (λ (a b) (not (equal? a b))) (se2 2 3) (se2 2 3))
(check-equal? (se2-x (se2 2 3)) 2)
(check-equal? (se2-y (se2 2 3)) 3)
(check-equal? (se2-x (car ((se2 2 3) 'c))) 2)
(check-equal? (se2-y (car ((se2 2 3) 'c))) 3)
(check-equal? (cdr ((se2 2 3) 'c)) 'c)
(check-not-exn (λ () (ann (car ((se2 2 3) 'c)) se2)))
(check-true (se2? (car ((se2 2 3) 'c))))
(check (λ (a b) (not (equal? a b))) (se3 4 5 "f") (se3 4 5 "f"))
(check-equal? (se2-x (se3 4 5 "f")) 4)
(check-equal? (se2-y (se3 4 5 "f")) 5)
(check-equal? (se3-z (se3 4 5 "f")) "f")
(check-equal? (se2-x (car ((se3 4 5 "f") 'd 'e))) 2)
(check-equal? (se2-y (car ((se3 4 5 "f") 'd 'e))) 3)
(check-equal? (let ([ret : Any (car ((se3 4 5 "f") 'd 'e))])
(if (se3? ret)
(se3-z ret)
"wrong type!"))
"f")
(check-equal? (cadr ((se3 4 5 "f") 'd 'e)) 'd)
(check-equal? (caddr ((se3 4 5 "f") 'd 'e)) 'e)
(check-equal? ((caddr ((se4 4 5 "f") 'd (λ ([x : Number]) (* x 2)))) 123)
246)
(check-not-exn (λ () (ann (car ((se3 4 5 "f") 'd 'e)) se2)))
(check-not-exn (λ () (ann (car ((se3 4 5 "f") 'd 'e)) se3)))
(check-true (se2? (car ((se2 2 3) 'd))))
(check-true (se3? (car ((se2 2 3) 'e))))]
@subsection{@racket[ann]}
@chunk[<ann>
(define-syntax/parse (new-ann value:expr (~optional :colon) type:expr)
(template (ann value (template-expand-type () type))))]
(template (ann value (tmpl-expand-type () type))))]
@chunk[<test-ann>
(let ()
@ -543,8 +658,8 @@ them.
(define-syntax/parse (new-inst v
(~optional :colon) t ...
(~optional (~seq last (~datum ...) b:id)))
(template (inst v (template-expand-type () t) ...
(?? (?@ (template-expand-type () last)
(template (inst v (tmpl-expand-type () t) ...
(?? (?@ (tmpl-expand-type () last)
(... ...) b)))))]
@chunk[<test-inst>
@ -577,8 +692,8 @@ them.
e:expr] ...)
. rest)
(template
(let (?? (?@ loop (?? (?@ : (template-expand-type tvars.vars
return-type)))))
(let (?? (?@ loop (?? (?@ : (tmpl-expand-type tvars.vars
return-type)))))
(?@ . tvars)
([(?@ . name.expanded) e] ...)
. rest)))]
@ -664,7 +779,7 @@ them.
@chunk[<make-predicate>
(define-syntax/parse (new-make-predicate type:expr)
(template (make-predicate (template-expand-type () type))))]
(template (make-predicate (tmpl-expand-type () type))))]
@chunk[<test-make-predicate>
(let ()
@ -781,7 +896,7 @@ yet.
do:
with-handlers
define-struct/exec:
define-struct/exec)]
#|define-struct/exec|#)]
@section{Future work}
@ -863,7 +978,8 @@ We can finally define the overloaded forms, as well as the extra
(require (for-syntax racket
racket/syntax
syntax/parse
syntax/parse/experimental/template)
syntax/parse/experimental/template
"../lib/low-untyped.rkt")
"../lib/low.rkt")
(require (submod ".." expander))
@ -880,6 +996,7 @@ We can finally define the overloaded forms, as well as the extra
[new-lambda lambda]
[new-lambda λ]
[new-struct struct]
[new-define-struct/exec define-struct/exec]
[new-ann ann]
[new-inst inst]
[new-let let]
@ -897,6 +1014,7 @@ We can finally define the overloaded forms, as well as the extra
<define>
<lambda>
<struct>
<define-struct/exec>
<ann>
<inst>
<let>
@ -921,6 +1039,7 @@ And, last but not least, we will add a @tc[test] module.
<test-define>
<test-lambda>
<test-struct>
<test-define-struct/exec>
<test-ann>
<test-inst>
<test-let>