Is there a function in Racket that returns a procedure's lambda-expression?
Asked Answered
F

1

5

In one variant of Common Lisp (I think it was CMUCL, but I might be wrong—I can't find it any more) there was a function that was (I think) called function-lambda-expression. If it got a procedure, it would print out the lambda expression that had generated it. Example:

(let ((my-thunk (lambda () (+ 1 2))))
    (write my-thunk)
    (write (function-lambda-expression my-thunk)))

This would print out something like:

#<PROCEDURE>
(LAMBDA () (+ 1 2))

It was terribly useful for debugging and exploring the language.

I'm looking for a function like this in Racket. I've looked through the Racket Documentation but I can't find anything like it. (I wouldn't be surprised if I overlooked it, however.) Is there an equivalent in Racket?

Felixfeliza answered 1/2, 2020 at 7:10 Comment(2)
Btw., in Common Lisp both write and function-lambda-expression are standard functions.Zymometer
@RainerJoswig Thanks! It's been a while, and I forgot.Felixfeliza
R
13

No. Racket's lambda produces a closure that does not remember its S-expression (or syntax object) form. It does typically remember its name (or its abbreviated source location, if no name can be inferred), and that's often enough to help with debugging. (See object-name.)

You can build your own variant of lambda that has this feature, using Racket's applicable structures and a simple macro. Here's a basic example:

#lang racket

(struct exp-closure (f exp)
  #:property prop:procedure (struct-field-index f))

(define-syntax-rule (exp-lambda formals . body)
  (exp-closure (lambda formals . body)
               (quote (exp-lambda formals . body))))

(let ([my-thunk (exp-lambda () (+ 1 2))])
  (printf "fun is ~v\n" my-thunk)
  (printf "exp is ~v\n" (exp-closure-exp my-thunk))
  (printf "result is ~v\n" (my-thunk)))

This produces

fun is #<procedure:...tmp/lambda.rkt:11:19>
exp is '(exp-lambda () (+ 1 2))
result is 3

A better version of this macro might propagate the source location of the macro use to the lambda expression it creates, or the inferred name (see syntax-local-infer-name), or both.

Repletion answered 1/2, 2020 at 11:14 Comment(1)
Yet another testament to Racket's flexibility and power… Thanks for not only answering the question, but giving me an alternate solution! :)Felixfeliza

© 2022 - 2024 — McMap. All rights reserved.