[racket] Saving function bodies in Beginning Student Language
Hi folks,
In trying to improve the Bootstrap[1] teachpacks, I've written (with
help[2]) a macro to save function bodies in a hashtable in the sky before
actually defining them. That way, I can programmatically break down a
function definition into its constituent pieces and show how they're
working, in a somewhat stepper-like way, but importantly different.
[1] http://www.bootstrapworld.org/
[2] http://www.stackoverflow.com/....
This macro works happily in every context except for the relevant one: the
beginning student language. BSL provides nice error messages, and bunches
of other things that we like, but this is the behavior we see:
Everywhere else:
> (define/save-source (foo x) (+ 3 x))
> (procedure-source foo)
'(» (x) (+ 3 x)) [lambda is written ? here due to ascii email]
> (procedure-name foo)
'foo
> (foo 10)
13
In BSL:
> (define/save-source (foo x) (+ x 3))
> (procedure-source foo)
(cons '? (cons (cons 'x empty) (cons (cons '+ (cons 'x (cons 3 empty)))
empty)))
> (procedure-name foo)
'foo
> (foo 6)
function call: expected a defined function name or a primitive operation
name after an open parenthesis, but found something else
So the define/save-source macro is
(define *procedure-name-hash* (make-hash))
(define *procedure-source-hash* (make-hash))
(define (save-source! fn name body)
(hash-set! *procedure-name-hash* fn name)
(hash-set! *procedure-source-hash* fn body))
(define (procedure-name fn)
(hash-ref *procedure-name-hash* fn false))
(define (procedure-source fn)
(hash-ref *procedure-source-hash* fn false))
;; define/save-source
;; the usual define syntax, but saves off the source for later access
;; with procedure-source
(define-syntax define/save-source
(syntax-rules ()
((_ (name formals ...) body-expressions ...)
(begin
(define name (? (formals ...) body-expressions ...))
(save-source! name 'name '(» (formals ...) body-expressions ...))))
((_ name value)
(define name value))))
And I guess the relevant conflicting piece of BSL is here:
http://pre.plt-scheme.org/racket/collects/lang/private/teach.rkt
In particular, this segment, which seems to check things about a function,
and set it up for the stepper:
;; Well-formed lambda def:
[(beginner-lambda arg-seq lexpr ...)
(begin
(check-function-defn-ok stx)
(let-values ([(defn bind-names)
(wrap-func-definition
#'name
(length (syntax->list #'arg-seq))
(lambda (name)
(with-syntax ([name name])
(quasisyntax/loc
stx
(define name
#,(stepper-syntax-property
(syntax-track-origin
#`(lambda arg-seq
#,(stepper-syntax-property
#`make-lambda-generative
'stepper-skip-completely #t)
lexpr ...)
lam
(syntax-local-introduce (car (syntax-e lam))))
'stepper-define-type
'lambda-define))))))])
(check-definition-new
'define
stx
#'name
defn
(and assign? bind-names))))]
So my question boils down to:
1. Is there a way that I can use the same info the stepper does, which is
saved here, so I don't have to define my own procedure-source in the first
place? or
2. Can I work with this to save off my source without bothering it or it
bothering me? or
3. Can the BSL get modified to support what I'm trying to do please?
Many thanks in advance, and also many thanks to those who created the
beginning student language for a terrific starting environment!
Grem
--
------ __@ Gregory A. Marton http://csail.mit.edu/~gremio
--- _`\<,_ 617-858-0775
-- (*)/ (*) Visualize Whirled Peas.
~~~~~~~~~~~~~~~~-~~~~~~~~_~~~_~~~~~v~~~~^^^^~~~~~--~~~~~~~~~~~~~~~++~~~~~~~