2012-02-07 2 views
1

В clojure макросы дают огромную мощность программисту. eval также очень мощный. Между ними существуют некоторые тонкие различия. Надеюсь, что эта загадка покажет свет на эту тему.Clojure riddle: eval, макросы и пространства имен

(ns hello) 
(defmacro my-eval [x] `~(read-string x)) 
(defn hello[] "Hello") 
(defn run-stuff [] 
    (println (hello)) 
    (println (my-eval "(hello)")) 
    (println (eval (read-string "(hello)")))) 
(ns main) 
(try (hello/run-stuff) 
    (catch Exception e (println e))) 

За 3 операторов внутри run-stuff тела, что один вызывает исключение, и почему другие нет?

Я сформулировал следующую загадку после исследования этого прекрасного вопроса Clojure - (read-string String calling function. Спасибо @Matthias Benkard за разъяснения

ответ

4

(println (hello)) и (println (my-eval "(hello)")) - полностью идентичные заявления - единственное различие заключается в том, что вас больше смущает ваш редактор. my-eval НЕ сопоставим с реальным eval. Разница в том, что аргумент my-eval должен быть строкой во время компиляции - следующие ошибки выходят из-за того, что символ x нельзя передать в строку.

(def x "(hello)") 
(my-eval x) 

my-eval Это делает совершенно бессмысленным - можно «Eval» символьной строки или вы можете удалить кавычки и my-eval и имеют одинаково функциональный код (что ваш редактор поймет).

Real eval, с другой стороны, пытается скомпилировать код во время выполнения. Здесь он терпит неудачу, потому что он запускается из пространства имен main, а не в пространстве имен hello, как указал @Matthias Benkard.