On Wed, May 4, 2011 at 7:03 PM, Simon Katz <nomisk...@gmail.com> wrote: > It is not possible to write out a function object (something returned > by lambda, Common Lisp's equivalent of fn) to a compiled file. No mix > of eval-when, separating functions and macros, and load order can > change that.
The same is not true of Clojure functions, though. Any function object reference can be turned in bytecode into a constructor call to the appropriate class -- with a closure, passing the appropriate argument. For example: user=> (class map) clojure.core$map user=> (.newInstance (class map)) #<core$map clojure.core$map@aea288> user=> (.invoke (.newInstance (class map)) inc [1 2 3 4 5]) (2 3 4 5 6) So, to embed map (not 'map or 'clojure.core/map, but map itself) in (eval `(~map inc [1 2 3 4 5])) you could generate the bytecode for this Java: (new clojure.core$map()).invoke(reference-to-inc-function, reference-to-1-2-3-4-5-vector); With a closure, it's slightly more complicated: user=> (def q (class (let [x 3] (fn [y] (+ x y))))) #'user/q user=> q user$fn__1501$fn__1502 user=> (.invoke (.newInstance (first (.getConstructors q)) (to-array [{} 4])) 42) 46 Note that instantiating the class with 4 gives us an add-4-to function instead of the original add-3-to function here. To actually convert that particular closure into code that reproduces it, the array of constructor arguments needs to be [{} 3]. (I'm not sure what the map argument is used for, but it seems to work when left empty, though not when omitted entirely. The compiler can always give closure objects metadata amounting to the correct [{} 3] or whatever needed to recreate the closure object by calling its class's constructor. The original problem *can* reappear with one step of regress *if* the constructor arguments include something the compiler doesn't knows how to turn into bytecode -- i.e. (eval (atom {})) still won't work, and so neither will (eval (let [x (atom {})] (fn [y] (reset! x y)))), but (eval (let [x 3] (fn [y] (+ x y)))) should work at that point as 3 is something that can already be turned into bytecode. Of course, for these trivial examples it's easy enough to turn the function or closure into a quoted expression that constructs it, such as (eval '(let [x 3] (fn [y] (+ x y)))). Where we run into problems is when we want to embed references to already-existing functions or other objects that lack global names. (There's an ugly workaround involving explicitly calling intern; you create a dummy namespace with a var holding the object, and then eval code that refers to that var by fully-qualified name in order to retrieve the object.) -- 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