Clojure - (чтение строки строка вызывающей функции - PullRequest
3 голосов
/ 06 февраля 2012

В файле clojure есть следующее:

(ns helloworld
  (:gen-class
    :main -main))

(defn hello-world-fn []
  (println "Hello World"))

(defn -main [& args]
  (eval (read-string "(hello-world-fn)")))

, и я запускаю его с

lein run helloworld

, и я получаю следующую ошибку:

Exception in thread "main" java.lang.RuntimeException: Unable to resolve symbol:
 helloworld in this context, compiling:(helloworld.clj:12)

У меня такое чувство, что мне нужно что-то сделать с ns-resolve или resolve, но я не добился успеха.Я пробовал следующее в основной функции:

(let [call-string  (read-string "(hello-world-fn)")
      func (resolve  (symbol (first call-string)))
      args (rest call-string)]
   (apply func args))

Без успеха.

Может ли кто-то (а) направить меня в правильном направлении;и (б) точно объяснить, что происходит в читателе Clojure, когда это происходит?

Ответы [ 2 ]

6 голосов
/ 06 февраля 2012

Попытайтесь увидеть, какое фактическое пространство имен находится внутри вашего -main.

(defn -main [& args]
  (prn *ns*)
  (eval (read-string "(hello-world-fn)")))

Он выводит #<Namespace user> перед тем как начать бомбардировку, за исключением. Это указывает на то, что выполнение программ с lein run начинается в пространстве имен user, которое, очевидно, не содержит сопоставления для вашего символа hello-world-fn. Вам нужно будет явно указать его.

(defn -main [& args]
  (eval (read-string "(helloworld/hello-world-fn)")))
3 голосов
/ 07 февраля 2012

Вы можете решить вашу задачу очень элегантно, используя macros. Фактически, вы можете написать макрос, который имитирует eval.

(defmacro my-eval [s] `~(read-string s))
(my-eval "(hello-world-fn)")); "Hello World"

Это работает лучше, чем eval, потому что разрешение символа s происходит в контексте, который вызывает my-eval. Спасибо @Matthias Benkard за разъяснения.

Вы можете прочитать о макросах и их синтаксисе в http://clojure.org/reader

...