[racket] obtaining name of module-level binding

From: Danny Yoo (dyoo at hashcollision.org)
Date: Tue Aug 7 16:47:58 EDT 2012

> Is 'Semantics Engineering with PLT Redex' where I should get started on
> language-engineering?

Concretely, I think Robby's suggestion will look something like this:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#lang racket

;; Let's create a custom structure for procedures that remember certain things.
(struct proc/data (proc data)
  #:property prop:procedure (lambda (pd . args)
                              (apply (proc/data-proc pd) args)))

;; We can manually create such instances...
(define f (proc/data
           ;; implementation:
           (lambda (x)
             (* x x))
           ;; with associated metadata:
           "this is the square function"))

;; It can be called:
(f 16)

;; but we can also retrieve its metadata:
(proc/data-data f)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

For more information on this, see:
http://docs.racket-lang.org/reference/procedures.html#(def._((lib._racket/private/base..rkt)._prop~3aprocedure))



Now that we can record metadata with a procedure-like value, let's
look at what kinds of data we'd like to capture.  Concretely, your
question sounds like you want something about module-level bindings.
That kind of information should be accessible at compile-time.  We can
try to write a macro to save that information for us.



Continuing: let's have a "def" form that remembers some information we
determine ate compile time.  Save the above coide into a file called
"def.rkt".  We'll be adding the following extra lines to it:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; I think we need the following definition to use splicing-let-syntax:
(require racket/splicing)

;; This "def" will try to automatically bundle a metadata or a
proc/data; this information is
;; the module path, which it can determine during compilation.
(define-syntax (def stx)
  (syntax-case stx ()
    [(_ (name . args) body ...)
     (syntax/loc stx

       ;; Question to others: how can this be simplified?
       (splicing-let-syntax ([get-literal-metadata
                              (lambda (stx)
                                #`(#%datum . #,(format "~s"
(variable-reference->resolved-module-path

(#%variable-reference)))))])
          (define name (proc/data
                        (lambda args body ...)
                        (get-literal-metadata)))))]))

(provide def
         (struct-out proc/data))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


I'm not sure if this is the cleanest way to do it, so hopefully
someone can help correct me.  :)


This creates a "def" form that can define functions.  It uses the
proc/data we defined earlier, and it does a minor bit of compile-time
computation to figure out module paths.


Finally, let's try using it!  Create 'def-test.rkt' with the following content:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#lang racket
(require "def.rkt")

(def (h x)
  (string-append "hi, I'm " x))

(h "bob")

(proc/data-data h)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

If you run this program, you should see:

##############################
"hi, I'm bob"
"#<resolved-module-path:'def-test>"
##############################


which shows that the "h" function we create with 'def' is a callable
thing, and it also has runtime metadata that remembers where it came
from.


For more information, see: http://docs.racket-lang.org/guide/pattern-macros.html

Posted on the users mailing list.