Динамическое связывание clojure, read-string и eval Невозможно разрешить символ

  (declare ^:dynamic symbol-table)
  (defn answer []
    (prn "blah")
    (binding [symbol-table {:answer 42}]
      (-> "[:h1 (:answer symbol-table)]" read-string eval)))

Приведенный выше код работает, как и ожидалось, когда выполняется в repl. это возвращается

cpress.hsp> (answer)
"blah"                                                                                                                                                                                      
[:h1 42]

Тем не менее, когда он выполняется в порождении потока через http-kit, я получаю неспособность разрешить символ

Exception in thread "Thread-43" 
java.lang.RuntimeException: Unable to resolve symbol: symbol-table in this context, compiling:(NO_SOURCE_PATH:0:0)
        at clojure.lang.Compiler.analyze(Compiler.java:6792)
        at clojure.lang.Compiler.analyze(Compiler.java:6729)
        at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3874)
        at clojure.lang.Compiler.analyzeSeq(Compiler.java:7005)
        at clojure.lang.Compiler.analyze(Compiler.java:6773)

чтобы смоделировать это в repl порождают поток, чтобы запустить функцию ответа

  (.. (Thread. answer) start)

Почему это происходит и как это исправить?

Некоторые эксперименты показывают, что он не может найти символ из-за пространства имен. например, вместо того, чтобы получить выражение из read-string, я вставил литерал

  (defn answer2 []
    (binding [symbol-table {:answer 42}]
      (prn (eval `[:h1 (:answer symbol-table)])) ;;works                                                                                                                                    
      ;;(eval '[:h1 (:answer symbol-table)]) ;; does not works                                                                                                                              
      ))

первый eval использует синтаксическое цитирование, которое работает, но когда я использую регулярное цитирование, оно не работает. синтаксическое цитирование разрешает пространство имен, в то время как обычное цитирование - нет. если бы read-string вернула выражение с символами, определенными в пространстве имен, то это решило бы мою проблему, я думаю, но read-string не

1 ответ

Решение

Когда вы запускаете eval, неквалифицированные символы в форме разрешаются в текущем пространстве имен во время выполнения (а не в пространстве имен, где определена функция).

Чтобы решить эту проблему, вы можете создать версию eval с пространством имен, привязанным к нужному:

(defn local-eval [x]
  (binding [*ns* (find-ns 'my-namespace)]
    (eval x)))

(Очевидно, вам нужно изменить my-namespace отражать правильное имя). Тогда вы используете это вместо:

(defn answer []
  (binding [symbol-table {:answer 42}]
    (-> "[:h1 (:answer symbol-table)]" read-string local-eval)))
Другие вопросы по тегам