guile's procedure-source in racket?
Does racket have something like guile's procedure-source function, e.g.:
(define (plus-one x) (+ 1 x))
(procedure-source plus-one开发者_如何学运维) --> (quote (+ 1 x))
I'm trying to make something akin to a debugging tool for beginning students, in which they can see partial or complete evaluations of a particular function while they play with its behavior in a 2htdp/universe. So I could use a macro for this case, except in their program I'd still like the definition to look exactly as usual, so I can't just have them quote it in the first place and eval it later, unless I redefine define... which might be okay, but I'd appreciate pointers on how best to do it.
The problem you're running into is due to a Beginner Student Language restriction: normally, higher-order functions are a syntactic error in the language, because beginners shouldn't know about them yet.
There's a way to opt-out of this. Your procedure-source can be labeled as one of the exceptions to this restriction, by using provide-higher-order-primitive, which is specifically meant to cooperate with BSL.
Here's what your library looks like with it:
#lang racket/base
(require lang/prim
racket/bool
(for-syntax racket/base))
(provide define/save-source)
(provide-higher-order-primitive procedure-name (fn))
(provide-higher-order-primitive procedure-source (fn))
(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-syntax define/save-source
(syntax-rules ()
((_ (name formals ...) body-expressions ...)
(begin
(define name (λ(formals ...) body-expressions ...))
(save-source! name 'name '(λ(formals ...) body-expressions ...))))
((_ name (λ(formals ...) body-expressions ...))
(begin
(define name (λ(formals ...) body-expressions ...))
(save-source! name 'name '(λ(formals ...) body-expressions ...))))
((_ name value)
(define name value))))
BSL programs that use this should be able to use procedure-name and procedure-source fine.
I've done something like this:
(provide (rename-out (def/help define)
(define-syntax/help define-syntax))
help)
(define-syntax def/help
(syntax-rules ()
((_ name description signature (λ(vs ...) exps ...))
(begin
(add-help! 'name description 'signature '(λ(vs ...)))
(define name (λ(vs ...) exps ...))))))
...
> (require "working.ss")
> (define (plus a b) (+ a b))
X define: bad syntax in: (define (plus a b) (+ a b))
> (define plus
"Add two numbers"
(int int -> int)
(λ(a b) (+ a b)))
> (help plus)
plus
Add two numbers
(int int -> int)
(λ (a b))
(Some meat is missing, only giving an idea.) It's not super robust as shown but is this the direction you are leaning?
This is what I ended up with:
(provide (rename-out (define/save-source define)) procedure-source)
then in the body
(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-syntax define/save-source
(syntax-rules ()
((_ (name formals ...) body-expressions ...)
(begin
(define name (λ(formals ...) body-expressions ...))
(save-source! name 'name '(λ(formals ...) body-expressions ...))))
((_ name (λ(formals ...) body-expressions ...))
(begin
(define name (λ(formals ...) body-expressions ...))
(save-source! name 'name '(λ(formals ...) body-expressions ...))))
((_ name value)
(define name value))))
and in the repl:
> (define/save-source (plus-one x) (+ 1 x))
> (procedure-source plus-one)
(λ (x) (+ 1 x))
> (plus-one 3)
4
>
What's odd is that in the student repl I get:
> (procedure-source update-target)
(cons 'λ (cons (cons 'x empty) (cons (cons '+ (cons 'x (cons 20 empty))) empty)))
> (update-target 30)
function call: expected a defined function name or a primitive operation name after an open parenthesis, but found something else
精彩评论