; Copyright (c) 1993-1999 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 ; ; ( ...) ; ; ; ; ; ( []) ; ... ; (( ...) ; ...)) ; ; This is equivalent to ; ; (define-record-type ; ; (maker name index ...) ; ; (name ) ; (index ) ; ( []) ; ...) ; ; (define ; (vector (maker 0 ) ; (maker 1 ) ; ...)) ; ; (define-dispatch-macro ; ( ...) ; ) ; ; 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 ( ...) ) ; ; This defines to be a macro ( X) that looks X up in ; the list of member names and returns the corresponding element of ; . ; ; (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) ((eq? elt (car names)) (list (,%code-quote ,%vector-ref) (rename1 ',elts) i)) (else (loop (cdr names) (+ i 1)))))))))) (vector-ref code-quote)) ; (define-enumerated-type ; ; ; ; ; ; ( ...)) ; ; 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 ; ; ; ; ; ; ((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) ...)))))