123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
- ; Finite types (i.e. record types with a fixed set of elements).
- ;
- ; An enumeration is really a special case of a finite type.
- ;
- ; (define-finite-type <id and dispatch-macro>
- ; <type name>
- ; (<constructor field name> ...)
- ; <predicate>
- ; <vector of elements>
- ; <name accessor>
- ; <index accessor>
- ; (<field name> <field accessor> [<field setter>])
- ; ...
- ; ((<element name> <constructor field value> ...)
- ; ...))
- ;
- ; This is equivalent to
- ;
- ; (define-record-type <id and dispatch-macro>
- ; <type name>
- ; (maker name index <constructor field name> ...)
- ; <predicate>
- ; (name <name accessor>)
- ; (index <index accessor>)
- ; (<field name> <field accessor> [<field setter>])
- ; ...)
- ;
- ; (define <vector of elements>
- ; (vector (maker <element name> 0 <constructor field value>)
- ; (maker <element name> 1 <constructor field value>)
- ; ...))
- ;
- ; (define-dispatch-macro <id and dispatch-macro>
- ; (<element name> ...)
- ; <vector-of-elements>)
- ;
- ; where DEFINE-DISPATCH-MACRO defines an ENUM-like dispatcher.
- ;
- ;(define-finite-type foo :foo ; id and type
- ; foo? ; predicate
- ; foo-elements ; vector containing all elements
- ; foo-name ; name accessor
- ; foo-index ; index accessor
- ; (color foo-color set-foo-color!) ; any additional fields
- ; ((name color) ; element pattern
- ; (a 'red) ; the elements themselves
- ; (b 'green)
- ; (c 'puce)
- ; (d 'taupe)))
- ;
- ; (foo a) -> #{foo a}
- (define-syntax define-finite-type
- (lambda (form rename compare)
- (let ((destruct (lambda (proc)
- (apply proc (cdr form))))
- (%define-record-type (rename 'define-record-type))
- (%define-record-discloser (rename 'define-record-discloser))
- (%define (rename 'define))
- (%begin (rename 'begin))
- (%lambda (rename 'lambda))
- (%vector (rename 'vector))
- (%list (rename 'list))
- (%define-dispatch (rename 'define-dispatch))
- (%make-immutable! (rename 'make-immutable!))
- (%maker (rename 'maker))
- (%name (rename 'name))
- (%index (rename 'index))
- (%blah (rename 'blah)))
- (destruct (lambda (foo :foo pattern foo? foo-elements foo-name foo-index
- . more)
- (let* ((fields (do ((more more (cdr more))
- (fields '() (cons (car more) fields)))
- ((or (null? more)
- (pair? (caar more)))
- (reverse fields))))
- (elts (car (reverse more)))
- (names (map car elts)))
- `(,%begin
- (,%define-record-type ,foo ,:foo
- (,%maker ,%name ,%index . ,pattern)
- ,foo?
- (,%name ,foo-name)
- (,%index ,foo-index)
- . ,fields)
- (,%define-record-discloser ,:foo
- (,%lambda (,%blah)
- (,%list ',foo (,foo-name ,%blah))))
- (,%define ,foo-elements
- (,%make-immutable!
- (,%vector . ,(do ((elts elts (cdr elts))
- (i 0 (+ i 1))
- (res '() `((,%maker ',(caar elts)
- ,i
- . ,(cdar elts))
- . ,res)))
- ((null? elts)
- (reverse res))))))
- (,%define-dispatch ,foo ,names ,foo-elements)))))))
- (define-record-type define-record-discloser define-dispatch
- define begin lambda vector list))
- ; (define-dispatch <name> (<member name> ...) <vector of members>)
- ;
- ; This defines <name> to be a macro (<name> X) that looks X up in
- ; the list of member names and returns the corresponding element of
- ; <vector of members>.
- ;
- ; (define-dispatch foo (a b c) members)
- ; (foo b) -expands-into-> (vector-ref members 1)
- (define-syntax define-dispatch
- (lambda (form0 rename0 compare0)
- (let ((name (cadr form0))
- (names (caddr form0))
- (elts (cadddr form0))
- (%vector-ref (rename0 'vector-ref))
- (%code-quote (rename0 'code-quote)))
- `(define-syntax ,name
- (lambda (form1 rename1 compare1)
- (let ((elt (cadr form1)))
- (let loop ((names ',names) (i 0))
- (cond ((null? names)
- form1)
- ((compare1 elt (car names))
- (list (,%code-quote ,%vector-ref) (rename1 ',elts) i))
- (else
- (loop (cdr names) (+ i 1))))))))))
- (vector-ref code-quote))
- ; (define-enumerated-type <id and dispatch-macro>
- ; <type name>
- ; <predicate>
- ; <vector of elements>
- ; <name accessor>
- ; <index accessor>
- ; (<element name> ...))
- ;
- ; This is a simplified version that has no additional fields. It avoids
- ; a lot of unnecessary parens around the element names.
- ;
- ; The above expands into:
- ;
- ; (define-finite-type <id and dispatch-macro>
- ; <type name>
- ; <predicate>
- ; <vector of elements>
- ; <name accessor>
- ; <index accessor>
- ; ((name)
- ; (<element name>)
- ; ...))
- (define-syntax define-enumerated-type
- (syntax-rules ()
- ((define-enumerated-type id type-name predicate elements
- name-accessor index-accessor
- (element ...))
- (define-finite-type id type-name () predicate elements
- name-accessor index-accessor
- ((element) ...)))))
|