I bumped into this:
(sci/eval-string "(require '[clojure.set :as set]) (set/union {}{})" opts)
=> {}
but
(sci/eval-form (sci/init {}) (edn/read-string "(require '[clojure.set :as set]) (set/union {}{})"))
Execution error (ExceptionInfo) at sci.impl.utils/throw-error-with-location (utils.cljc:52).
Could not resolve symbol: clojure.set
how can I interpret a form previously read by edn/read-string
? Or do I have to use the sci version?let me take a look
@katox ah I see. the EDN you read is not well-formed as clojure code due to EDN supporting quotes as single things, they are not related to what follows. It's just an ordinary symbol.
user=> (edn/read-string "'[1 2 3]")
'
compare:
user=> (def form (read-string "(do (require '[clojure.set :as set]) (set/union #{1 2} #{2 3}))"))
#'user/form
user=> (sci/eval-form (sci/init {}) form)
#{1 3 2}
hmm, if I replace the quote symbol with the actual quote
function it still doesn't do the thing
user=> (def form (edn/read-string "(do (require (quote [clojure.set :as set])) (set/union {}{}))"))
#'user/form
user=> form
(do (require (quote [clojure.set :as set])) (set/union {} {}))
user=> (sci/eval-form (sci/init {}) form)
{}
edn/read-string only reads the first form
right!
what was the original problem - it was a "configuration" file with two functions in it
i wanted to read it in with edn and run those functions through sci (only those)
what approach would you use? just read it all using sci parser?
@katox I think you can also use edamame for this: it allows parsing EDN++, where ++ is just the amount you need
edn++, nice 😄
but you can also just use the sci parser for this
things like these get tricky soon, you must have a galaxy brain
thanks a lot, I'll try to get that in
another thing - is there a convenience function to import the whole ns into sci :namespaces
?
not really, but you can do this using ns-publics + sci/copy-var
I use this
(defn map-sym [ns syms]
(into {} (map (fn [sym] [sym @(resolve (symbol (name ns) (name sym)))]) syms)))
but kinda too simplistic 🙂that works too. note that if you're compiling down to a native-image, having resolve in a function body isn't great for size
but if you're doing this on the top-level it should not be a problem
the ns will be compiled in, the require is there only to alias syms
will alias
be better?
@katox What I mean is: if you use map-sym
only on top-level values, that's ok, but if you use this at run-time in the graalvm binary, it will add 10-20 MB to the binary for nothing
Oops, sorry, I mean https://github.com/borkdude/dynaload
Resolve holds on to too much stuff, this is why you will get a fatter binary
I see it's about the resolve
function itself
yes. so:
(def my-namespace (map-sym ...))
is good, but:
(defn foo [x] (get (map-sym ...) x))
is not that great for binary size.A relatively simple graalvm binary with java 11 and clojure 1.10.2-alpha3 yields about 11mb. When you accidentally use resolve at runtime it will become 25mb.
The first could do, it's a constant environment. I am just too lazy to enumarate the whole libary ns and top level syms. ns-publics + copy-var should do the same thing (if all symbols are imported)
yeah, generating a constant at compile time, that's the way to do it.
sounds like that works fine.
thanks for insights