Printing and reading a function
I've been trying to do some generic work on serializing clojure objects, and am much impressed with how easy and functional it is, as well as how easy it is to extend this to other objects (eg Java classes). However, I seem to come a little unstuck when it comes to functions / closures. I realise capturing the state of the environment is going to be tricky at best, but at the moment I'm trying to extend the basic defn macro to capture the code used to define the function. I then tried using print-dup to print the source string from the meta data, but this is where things stop working. As far as I can see from the clojure/core-print.clj file, doing a (binding [*print-dup* true] (pr-str function)) should print out the meta-data of the function as well, but this does not seem to be happening. I want this to happen, as I need access to the metadata to dump the code used instead of the default #=(user $eval__17$function__19. ) string. Essentially my new version of defn is a basic wrapper around defn: (defmacro mkfn [nm args func] (list 'defn nm {:source (str "(mkfn " nm " " args " " func ")")} args func)) so when you do (mkfn test1 [a b] (+ a b)) you get out a function test1 with a metadata :source tag (meta (var test1)) {:ns #, :name test1, :file "NO_SOURCE_PATH", :line 439, :arglists ([a b]), :tag "sometag", :source "(mkfn test1 [a b] (+ a b))"} I tried to override the print-dup for clojure.lang.Fn to check for the :source meta-data tag, but I keep getting NullPointerExceptions. Anyone got any ideas? Am I missing something obvious? (defmethod print-dup clojure.lang.Fn [o w] (if (meta o) (.write w (:source (meta o))) (print-ctor o (fn [o w]) w))) --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
Re: Save current namespace like a Smalltalk image
I had the same thought (as posted in the other thread) and haven't come to a final solution yet. The main reason I wanted to achieve it was that I do my developing / tinkering / brainstorming spread over several work boxes spread out through several locations, and a clojure REPL is cheap and easy, whereas maintaining several IDEs in synch (3 locations at work, 2 at home) can be a bit of a nightmare. The compromise I've got at the moment is that I've made a custom wrapper around [defn] that records the code used to create the instance, and stores it in the metadata of the var that points to the function. I can then cycle through the namespace definitions using ns- interns / ns-publics and see the definition of each function, and can save it to a file. I tried to create a print-dup method so that the entire contents of a namespace could be dumped to a file, but as chouser pointed out, print- dup works on the function itself, whereas the code is stored in the metadata of the var that points to the function (and there's no back- link from the function to the var), so now it is a multi-stage process to port current code in its entirety, but as I'm generally only working on fairly limited areas of code it isn't a huge deal. Also, any closures are not captured by capturing the source, so there's still issues there, but for me the function definition is generally good enough. Still have to implement it for macros as well, but haven't needed that as much. Incidentally, I find the easiest way to port my code around is to print it to the repl, then cut-and-paste it to etherpad, which I can then access from anywhere (without having to save). Now if only there was a hosted REPL that integrated an IDE nicely I would really be set. Lord-of-all-repls comes close, but is not pure clojure or JVM. Jurjen On Jul 8, 8:13 pm, Robert Campbell wrote: > Hello, > > Sometimes I have pretty long REPL sessions where I'm trying to flesh > out some ideas. When I close my instance of Clojure Box (Emacs based) > I lose all the definitions I had worked out over time. Is there any > way to dump namespace(s) to an image? It would be great to be able to > load up some workspace image and pick up where I left off. > > Rob --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
Re: Save current namespace like a Smalltalk image
I seem to be lagging a little in the conversation, but for what it's worth, the code I use to capture function definitions is: (defmacro mkfn "Create a function and record the source in the var metadata" [name & fdecl] (list* `defn (with-meta name (assoc (meta name) :source (str (list* `mkfn name fdecl fdecl)) which is based on the macro [defn-] (from clojure.core) so will work exactly as [defn] does. To get the source back, you need to access the metadata of the var that points to the function, so for (mkfn test [a b] (+ a b)) you would use (meta (var test)). I also thought about keeping previous definitions (like version control) because I tend to occasionally destroy perfectly fine functions. This could be done by changing the assoc line to keep a list of definitions, but tends to cause a bit of clutter... I can then dump any namespace to a string (to write to a file / post to net / etc) (mkfn get-ns "Prints the public contents of the given namespace" [ns] (map #(if (:source (meta (second %1))) ; check if source was recorded (:source (meta (second %1))) (if (:macro (meta (second %1))) '() ; macros not handled yet... (list 'def (binding [*print-dup* true]; else use generic print- dup (pr-str (second %1)) (pr-str (first %1))) (eval (first %1) (ns-publics ns))) ; over all public vars in ns This still has some issues, especially if you have defined some unbound vars, so is still very much a work-in-progress. As you might note, macros aren't handled yet as print-dup tends to throw exceptions on them when it encounters (eval (first %1)). Also note that any functions defined by [defn] will be printed as (defn func #) so when reading back in, the reader will choke on the #<...> form (CompilerException java.lang.RuntimeException: java.lang.Exception: Unreadable form) Hope its useful for you, your mileage may vary (greatly, I expect) If I get it down to something useful and reasonably functional, I'll submit it to clojure.contrib, but for now that's about all I use. Jurjen On Jul 8, 11:46 pm, Robert Campbell wrote: > Hi Jurjen, > > That wrapper for defn is something I was looking for in another post; > I previously asked how I can inspect the definitions of my functions > on the REPL. When I'm exploring stuff I'll be redefining many > functions many times and sometimes I lose track things. I basically > have to scroll around searching my REPL for the last definition. It > sounds like you have a solution to this problem. It seems strange to > me that Clojure doesn't support this concept natively. At some point > the function definition is compiled into bytecode to run on the JVM, > why not just automatically safe the original definition in metadata > when this is done? Have you should about adding your wrapper code to > Contrib? > > Rob > > > > On Wed, Jul 8, 2009 at 12:30 PM, Jurjen wrote: > > > I had the same thought (as posted in the other thread) and haven't > > come to a final solution yet. The main reason I wanted to achieve it > > was that I do my developing / tinkering / brainstorming spread over > > several work boxes spread out through several locations, and a clojure > > REPL is cheap and easy, whereas maintaining several IDEs in synch (3 > > locations at work, 2 at home) can be a bit of a nightmare. > > > The compromise I've got at the moment is that I've made a custom > > wrapper around [defn] that records the code used to create the > > instance, and stores it in the metadata of the var that points to the > > function. I can then cycle through the namespace definitions using ns- > > interns / ns-publics and see the definition of each function, and can > > save it to a file. > > > I tried to create a print-dup method so that the entire contents of a > > namespace could be dumped to a file, but as chouser pointed out, print- > > dup works on the function itself, whereas the code is stored in the > > metadata of the var that points to the function (and there's no back- > > link from the function to the var), so now it is a multi-stage process > > to port current code in its entirety, but as I'm generally only > > working on fairly limited areas of code it isn't a huge deal. > > Also, any closures are not captured by capturing the source, so > > there's still issues there, but for me the function definition is > > generally good enough. Still have to implement it for macros as well, > > but haven't needed that as much. > > > Incidentally, I find the easiest way to port my code around is to > > print it to the repl, then cut-and-paste it