Reputation: 35762
I've got the following in a clojure file:
(ns helloworld
(:gen-class
:main -main))
(defn hello-world-fn []
(println "Hello World"))
(defn -main [& args]
(eval (read-string "(hello-world-fn)")))
and I'm running it with
lein run helloworld
and I'm getting the following error:
Exception in thread "main" java.lang.RuntimeException: Unable to resolve symbol:
helloworld in this context, compiling:(helloworld.clj:12)
I have a feeling I need to do something with ns-resolve
or resolve
but I haven't had any success. I've tried the following in the main function:
(let [call-string (read-string "(hello-world-fn)")
func (resolve (symbol (first call-string)))
args (rest call-string)]
(apply func args))
Without success.
Can someone (a) point me in the right direction; and (b) explain precisely what is going on in the Clojure reader when this occurs?
Upvotes: 3
Views: 1351
Reputation: 20710
You can solve your challenge, in a very elegant way, using macros
. In fact, you can write a macro that mimics eval
.
(defmacro my-eval [s] `~(read-string s))
(my-eval "(hello-world-fn)")); "Hello World"
It works better that eval
because the symbol resolution of s
occurs in the context that calls my-eval
. Thanks to @Matthias Benkard for the clarifications.
You can read about macros and their syntax in http://clojure.org/reader
Upvotes: 3
Reputation: 657
Try to see what the actual namespace is inside your -main
.
(defn -main [& args]
(prn *ns*)
(eval (read-string "(hello-world-fn)")))
It outputs #<Namespace user>
before bombing out with the exception. This hints that execution of programs with lein run
starts out in the user
namespace, which obviously does not contain the mapping for your hello-world-fn
symbol. You'll need to explicitly qualify it.
(defn -main [& args]
(eval (read-string "(helloworld/hello-world-fn)")))
Upvotes: 6