5

How do I write a function to resolve a symbol in a lexical environment?

(let [foo some-var]
  (let [sym 'foo]
    (resolve-sym sym)))

I want to get the var that 'foo is bound to.

Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
navgeet
  • 987
  • 1
  • 10
  • 23
  • 3
    Let doesn't create new vars, so basically you cant resolve them – Ankur Mar 24 '13 at 15:54
  • But it is possible to get the enviroment inside a macro with &env. – navgeet Mar 24 '13 at 15:59
  • @navgeet, no, it is not possible. `(defmacro m [x & env] '(x env))` will expand in this way: `(m 1 2 3 4 5) -> '(1 (2 3 4 5))`, i.e. `& env` will give you access to varargs. There is no way in Clojure to get current lexical environment. – Vladimir Matveev Mar 24 '13 at 16:17
  • 3
    @VladimirMatveev, navgeet isn't talking about varags. http://blog.jayfields.com/2011/02/clojure-and.html – Jeremy Mar 24 '13 at 16:20
  • 5
    @navgeet: Can you post what problem you are trying to solve? May be there is better way to do it – Ankur Mar 24 '13 at 16:21

2 Answers2

4

I am not completely sure why I want something like this, but looks like it can certainly be done. from http://clojuredocs.org/circumspec/circumspec.should/local-bindings

(defmacro local-bindings
  "Produces a map of the names of local bindings to their values.
   For now, strip out gensymed locals. TODO: use 1.2 feature."
  []
  (let [symbols (remove #(.contains (str %) "_")
                        (map key @clojure.lang.Compiler/LOCAL_ENV))]
    (zipmap (map (fn [sym] `(quote ~sym)) symbols) symbols)))


(let [foo 1 bar 2]
  (local-bindings))
=> {foo 1, bar 2}
navgeet
  • 987
  • 1
  • 10
  • 23
1

Here is both more, less and skew to than you wanted:

(define (make-let-core name value body)
  `(CORE LET ,name ,value ,body))

(define (env-extend env a-name its-denotation)
  (lambda (name)
    (if (equal? name a-name)
        its-denotation
        (if env (env name) 'unknown))))

(define (env-base)
  (lambda (name)
    (if (member name '(let resolve-sym #| ... |#))
        'syntactic-keyword
        'unknown)))

(define (expand exp env)
  (cond ((literal? exp) ...)
        ((symbol?  exp) ...)
        ((list? exp)
         (let ((operator (car exp))
               (operands (cdr exp)))
           (cond ((symbol? operator)
                  (case (env operator)
                    ((syntactic-keyword)
                     (case operator
                       ((let)
                        (let ((bound-name  (caar  operands))
                              (bound-value (cadar operands))
                              (body (cdr operands)))
                          (make-let-core bound-name
                                         (expand bound-value env)
                                         (expand body
                                                 (env-extend bound-name
                                                             'variable)))))
                       ((resolve-sym)
                        (let ((name (car operands)))
                          ;; right here
                          ...))
                       (...)))
                    ((variable) ;; function call
                     ...)

                    ((unknown)  ;; syntax error
                     ...)))

                 ((list? operator) ;; function call
                  ...)

                 (else ;; syntax error
                  ...))))
        (else ;; syntax error
         ...)))
GoZoner
  • 67,920
  • 20
  • 95
  • 145