7.2
9 User API for variants
9.1 Introduction
For convenience, we write a variant form, which is a thin wrapper against (U (~or constructor tagged) …).
9.2 Implementation of variant
In define-variant, we only define the type (which is the union of all the possible constructors. We do not bind identifiers for the constructors, for two reasons: the same constructors could appear in several variants, so we would define them twice, and it is likely that a constructor will have the same identifier as an existing variable or function.
(begin-for-syntax (define-syntax-class constructor-or-tagged (pattern [constructor-name:id . (~or ([field:id C:colon type:expr] …) (type:expr …))])))
«variant» ::=
(define-type-expander (variant stx) (syntax-parse stx [(_ :constructor-or-tagged …) (template (U (?? (tagged constructor-name [field C type] …) (constructor constructor-name type …)) …))]))
9.3 Predicate
«variant?» ::=
(define-syntax/parse (variant? :constructor-or-tagged …) (template (λ (v) (or (?? ((tagged? constructor-name field …) v) (constructor? constructor-name v)) …))))
9.4 define-variant
«define-variant» ::=
(define-syntax/parse (define-variant variant-name (~optkw #:debug) (~maybe #:? name?) (~maybe #:match variant-match) (~and constructor-or-tagged :constructor-or-tagged) …) (define/with-syntax default-name? (format-id #'name "~a?" #'name)) (define/with-syntax default-match (format-id #'name "~a-match" #'name)) (define-temp-ids "pat" ((type …) …)) (define-temp-ids "match-body" (constructor-name …)) (template (begin (define-type variant-name (variant [constructor-name (?? ([email protected] [field C type] …) ([email protected] type …))] …)) (define-syntax (?? variant-match default-match) (syntax-rules (constructor-name … (?? ([email protected] field …)) …) [(_ v [(constructor-name (?? ([email protected] [field pat] …) (pat …))) . match-body] …) (match v (?? [(tagged constructor-name [field pat] …) . match-body] [(constructor constructor-name pat …) . match-body]) …)])) (define-multi-id (?? name? default-name?) #:else #'(variant? constructor-or-tagged …)))))
9.5 Conclusion
«*» ::=
(require (for-syntax racket/base racket/list syntax/parse syntax/parse/experimental/template racket/syntax phc-toolkit/untyped type-expander/expander) phc-toolkit multi-id type-expander "constructor.hl.rkt" "structure.hl.rkt") (provide variant variant? define-variant) «constructor-or-tagged-stx-class» «variant» «variant?» «define-variant»