|
Links to Scheme resources, or quotes from them will appear on this page or subpages. (I first added this page to quote these 1993 macros for using EOPL under MacGambit.) |
¶
eopl macros
(1993) David McCusker as quoted in Michael Elhadad's 2000 "Advanced Topics in Programming Languages" class notes for using EOPL under MzScheme/DrScheme:
;;; MacGambit macros implementing records for the book:
;;;
;;; "Essentials of Programming Languages", Daniel P. Friedman,
;;; Mitchell Wand and Christopher T. Haynes, MIT Press, 1992.
;;;
;;; (C) Copyright 1993 David McCusker
(define-macro define-record (lambda (rec-name rec-fields)
`(let*
((sym string->symbol)
(str symbol->string)
(cat string-append)
(vec-len (+ 1 (length ',rec-fields)))
(name ',rec-name)
(name-str (str ',rec-name))
(make-name (sym (cat (str 'make-) name-str)) )
(name? (sym (cat name-str "?")))
(index 0))
(eval
`(define ,make-name
(lambda values (apply vector ',name values))))
(eval
`(define ,name?
(lambda (obj)
(and (vector? obj)
(= (vector-length obj) ,vec-len)
(eq? (vector-ref obj 0) ',name)))))
(for-each
(lambda (f)
(set! index (+ index 1))
(let* ((name->field (sym (cat name-str "->" (str f))))
(problem (cat (str name->field) ": bad record")))
(eval
`(define ,name->field
(lambda (obj)
(if (,name? obj)
(vector-ref obj ,index)
(error ,problem obj)))))))
',rec-fields)
name)))
(define every?
(letrec
((all?
(lambda (proc list)
(if (pair? list)
(if (proc (car list))
(all? proc (cdr list))
#f)
(if (null? list) #t (error "every?: not a list" list))))))
all?))
(define-macro variant-case (lambda (record-var . clauses)
(let*
((sym string->symbol)
(str symbol->string)
(cat string-append)
(exp (gensym))
(type? (lambda (name) (list (sym (cat name "?")) exp)) )
(good?
(lambda (c)
(and (pair? c)
(or (eq? 'else (car c))
(and (symbol? (car c))
(pair? (cdr c))
(list? (cadr c))
(every? symbol? (cadr c)))))))
(check-clause-syntax
(lambda (c)
(if (not (good? c))
(error
"variant-case: expected syntax (name field-list ...)" c))))
(make-clause
(lambda (c)
(let*
((n (str (car c)))
(n->f (lambda (f)
(list f (list (sym (cat n "->" (str f))) exp)))))
(if (eq? 'else (car c))
c
(list (type? n)
(cons 'let (cons (map n->f (cadr c)) (cddr c)))))))))
(for-each check-clause-syntax clauses)
`(let ((,exp ,record-var))
(cond ,@(map make-clause clauses))))))
|