Headache
Headache

Reputation: 13

Is there a Scheme toString method for a procedure?

I want to be able to take a procedure and see what it looks like. Is this possible?

For example, let's say I have:

(define (some-func x)
  (+ x 1))

What I want to do is apply some amazing function (say, stringify) to some-func and be able to look at its guts.

\> (stringify some-func)
"(lambda (x) (+ x 1))"

I haven't found any Racket libraries that do it. Can it be done?!

Upvotes: 1

Views: 549

Answers (2)

GoZoner
GoZoner

Reputation: 70135

Note, you could easily implement a define alternative to keep the source around. You don't avoid the lexical issues but, modulo that, you've got something with limited use.

(define name->source-mapping '())

(define (name->source name)
  (cond ((assq name name->source-mapping) => cdr)
        (else #f)))

(define (name->source-extend name source)
  (set! name->source-mapping (cons (cons name source) name->source-mapping))

(define-syntax define-with-source
  ((_ (name args ...) body1 body2 ...)
   (define name
     (begin (name->source-mapping-extend 'name '(lambda (args ...) body1 body2 ...))
                                             name->source-mapping))
            (lambda (args ...) body1 body2 ...)))))

[Above does not replace (define name value) syntax; consider the above an example only.]

Upvotes: 0

C. K. Young
C. K. Young

Reputation: 223003

In R6RS, there is no sure way to determine if two procedures are equivalent; even an expression like (let ((p (lambda () 42))) (eqv? p p)) is not guaranteed to be true.

R7RS addresses that by using the concept of "location tags", where each lambda expression generates a unique location tag. Then eqv? works for procedures by comparing location tags: thus, (let ((p (lambda () 42))) (eqv? p p)) is true, and (eqv? (lambda () 42) (lambda () 42)) is false.

There is no reliable way to get the source of a procedure (many implementations macro-expand and compile the procedures, discarding the original source), and even if you could, you could not use it to compare if two procedures are "equal", because of closures (and that two procedures could have the same "source" but have their free variables bound to different things). For example, consider the two expressions (let ((x 1)) (lambda () x)) and (let ((x 2)) (lambda () x)). They have the same "source", but nobody in their right mind would claim that they are equivalent in any way.

Upvotes: 3

Related Questions