[racket] writing a define-world macro

From: Todd O'Bryan (toddobryan at gmail.com)
Date: Sun Jul 25 16:16:12 EDT 2010

Because it can get really annoying to have to retrofit a whole program
when you add a bit of extra state to a world, Barry Brown first
suggested and then I--having completely forgotten about Barry's
suggestion--re-suggested that worlds include functional update
functions, so that changing a single field in a world didn't require
students to include boilerplate code to leave all the other fields
unchanged.

I think the following macro just about does this:

#lang racket
(provide define-world)

(define-for-syntax (build-name id . parts)
  (datum->syntax
   id
   (string->symbol
    (apply string-append
           (map (lambda (p)
                  (cond
                    [(syntax? p) (symbol->string (syntax-e p))]
                    [(symbol? p) (symbol->string p)]
                    [(string? p) p]))
                parts)))
   id))

(define-for-syntax (updater id fields field)
  (let ([name (build-name id id '- 'update- field)]
        [instance (build-name id 'a- id)]
        [constructor (build-name id 'make- id)])
    `(define (,name ,instance val)
       (,constructor ,@(for/list ([f fields])
                          (if (equal? f field)
                              'val
                              `(,(build-name id id '- f) ,instance)))))))

(define-syntax (define-world stx)
  (syntax-case stx ()
    [(_ id fields)
     (let ([field-names (syntax->list #'fields)])
       #`(begin
           (define-struct id fields)
           #,@(for/list ([f field-names])
              (updater #'id field-names f))))]))

How do I provide tests, and is there any chance something like this
could end up in 2htdp/universe?

Todd


Posted on the users mailing list.