I asked a related question here: Clojure: How do I turn clojure code into a string that is evaluatable? It mostly works but lists are translated to raw parens, which fails
The answer was great but I realized that is not exactly what I needed. I simplified the example for stackoverflow, but I am not just writing out datum, I am trying to write out function definitions and other things which contain structures that contain lists. So here is a simple example (co-opted from the last question).
I want to generate a file which contains the function:
(defn aaa []
(fff :update {:bbb "bbb" :xxx [1 2 3] :yyy (3 5 7)}))
Everything after the :update is a structure I have access to when writing the file, so I call str on it and it emerges in that state. This is fine, but the list, when I load-file on this generated function, tries to call 3 as a function (as it is the first element in the list).
So I want a file which contains my function definition that I can then call load-file and call the functions defined in it. How can I write out this function with associated data so that I can load it back in without clojure thinking what used to be lists are now function calls?
You need to
quotethe structure prior to obtaining the string representation:where
foois the structure.Three additional remarks:
traversing the code to quote all lists / seqs would not do at all, since the top-level
(defn ...)form would also get quoted;lists are not the only potentially problematic type — symbols are another one (
+vs.#<core$_PLUS_ clojure.core$_PLUS_@451ef443>);rather than using
(str foo)(even withfooalready quoted), you’ll probably want to print out the quotedfoo— or rather the entire code block with the quotedfooinside — usingpr/prn.The last point warrants a short discussion.
prexplicitly promises to produce a readable representation if*print-readably*istrue, whereasstronly produces such a representation for Clojure’s compound data structures “by accident” (of the implementation) and still only if*print-readably*istrue:The above behaviour is due to
clojure.lang.RT/printString‘s (that’s the method Clojure’s data structures ultimately delegate theirtoStringneeds to) use ofclojure.lang.RT/print, which in turn chooses output format depending on the value of*print-readably*.Even with
*print-readably*bound totrue,strmay produce output inappropriate forclojure.lang.Reader‘s consumption: e.g.(str "asdf")is just"asdf", while the readable representation is"\"asdf\"". Use(with-out-str (pr foo))to obtain a string object containing the representation offoo, guaranteed readable if*print-readably*istrue.