Erro de avaliação do símbolo Clojure
-
28-10-2019 - |
Pergunta
Portanto, atualmente tenho este código:
(ns contact-form.core
(:gen-class))
(def foo "Hello World!")
(defn some-func [a-symbol]
(println (str a-symbol "'s value is: " (eval a-symbol))))
(defn -main [& args]
(some-func 'foo))
Depois de fazer C-c C-k
no Emacs, obtenho a seguinte saída:
contact-form.core> (-main)
foo's value is: Hello World!
nil
Mas quando executo lein uberjar
e executo o arquivo jar resultante, recebo um erro:
Exception in thread "main" java.lang.RuntimeException: Unable to resolve symbol: foo in this context, compiling:(NO_SOURCE_PATH:0)
at clojure.lang.Compiler.analyze(Compiler.java:6235)
at clojure.lang.Compiler.analyze(Compiler.java:6177)
at clojure.lang.Compiler.eval(Compiler.java:6469)
at clojure.lang.Compiler.eval(Compiler.java:6431)
at clojure.core$eval.invoke(core.clj:2795)
at contact_form.core$some_func.invoke(core.clj:7)
at contact_form.core$_main.doInvoke(core.clj:10)
at clojure.lang.RestFn.invoke(RestFn.java:397)
at clojure.lang.AFn.applyToHelper(AFn.java:159)
at clojure.lang.RestFn.applyTo(RestFn.java:132)
at contact_form.core.main(Unknown Source)
Caused by: java.lang.RuntimeException: Unable to resolve symbol: foo in this context
at clojure.lang.Util.runtimeException(Util.java:156)
at clojure.lang.Compiler.resolveIn(Compiler.java:6720)
at clojure.lang.Compiler.resolve(Compiler.java:6664)
at clojure.lang.Compiler.analyzeSymbol(Compiler.java:6625)
at clojure.lang.Compiler.analyze(Compiler.java:6198)
... 10 more
Portanto, tenho duas perguntas:
- Por que o uberjar não funciona exatamente da mesma forma que o REPL?
- O que posso fazer para resolver este problema?
Solução
1. Por que o uberjar funciona de maneira diferente do REPL?
Uma causa do erro "NO_SOURCE_PATH" é que você não está no namespace que definiu 'foo.
Para ilustrar: se eu avaliar seu código em meu REPL e executá-lo, ele me coloca no namespace contact-form.core
como você esperaria, porque (ns contact-form.core)
é avaliado pelo REPL, mas se eu mudar para o namespace user
e chamar -main
, posso produz o mesmo erro:
contact-form.core=> (-main)
foo's value is: Hello World!
nil
contact-form.core=> (ns user)
nil
user=> (contact-form.core/-main)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: foo in this context, compiling:(NO_SOURCE_PATH:120)
user=>
Portanto, ao especificar seu ponto de entrada para main
para execução autônoma de uberjar (fora do REPL), é equivalente a chamar (contact-form.core/-main)
do namespace padrão em seu jar que é clojure.core
, porque (ns contact-form.core
) não foi avaliado. Resultado: main
pode ser executado com um caminho totalmente qualificado (espaço de nomes) para a função, mas nenhum dos símbolos de contact-form.core
estão disponíveis no namespace padrão atual.
2. A correção
A solução seria alternar explicitamente para o seu namespace primeiro:
(defn -main [& args]
(use 'contact-form.core)
(some-func 'foo))