开发者

guile's procedure-source in racket?

开发者 https://www.devze.com 2023-03-12 15:29 出处:网络
Does racket have something like guile\'s procedure-source function, e.g.: (define (plus-one x) (+ 1 x))

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
0

精彩评论

暂无评论...
验证码 换一张
取 消