Search code examples
clojureresolve

Clojure - (read-string String calling function


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?


Solution

  • 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