On May 4, 2016, at 6:08 PM, Johannes <bra...@nordakademie.de> wrote:

> okay, but why does the following work without quotation?
> user> (def f- (let [v 1
>               f (fn [x] x)] f))
> ;; => #'user/f-
> user> (eval {:d f-})
> ;; => {:d #function[user/fn--14679/f--14680]}
> user>  
> 
> The problem is that the place in my program where I give the map containing 
> the function object to eval, the map cannot be quoted.

Hmm, I thought I had read “eval doesn’t accept function objects” in a couple 
places on the Internet, but when I checked this page:
http://clojure.org/reference/evaluation
I found the sentence "Any object other than those discussed above will evaluate 
to itself.” So, it appears to be a bug, either in the documentation or in eval.

I’m only a Clojure noob, having started four weeks ago. so we’ll both have to 
wait for a more authoritative explanation from someone more familiar with 
Clojure internals. The reason I know about this (or thought I did) is because I 
recently struggled with a similar problem: dynamically supplying a method map 
to extend a protocol to a record. My solution was to define a top-level 
dynamically rebindable symbol and refer to it inside the expression passed to 
eval, something like this (untested code):

(def ^:dynamic method-map-holder)

(def dynamic-def-record [record-sym fields-vector method-map]
  (binding [method-map-holder method-map]
    (eval `(defrecord ~record-sym ~fields-vector))
    (eval `(extend ~record-sym
                   ~'my-project.core/MyProtocol
                   method-map-holder))))

The trick is to call binding to put the method-map (containing function 
objects) into a place where eval can see it. That place is: bound to a 
top-level symbol, which also appears in the object passed to eval. Note that 
inside the ` form passed to eval, method-map-holder is not preceded by a tilde. 
eval will see that exact symbol (qualified by the enclosing namespace). The 
point of all this is to avoid evaluating the map before passing it to eval.

Be aware that the above is an ugly hack, and probably not the best way to do 
it. I showed my actual code to someone with years of Clojure experience, and he 
immediately said, “Calling eval is a code smell: there’s almost always a better 
way to do what you’re trying to do,” and we quickly found a likely way to do 
what I needed with a macro. However, we did not find a way around temporarily 
binding the method-map to a dynamically rebindable symbol.

--
Ben Kovitz
http://mypage.iu.edu/~bkovitz/


-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to