clojure - 动态变量、绑定(bind)、命名空间可见性

标签 clojure

从原始命名空间的 n 层调用时动态变量未解析

设置:

File a.clj
-----------
(ns a)

(def ^:dynamic *poof* "poof")

(def x [1 '*poof* 3])

(defn- func-wbind [new-term]
  (binding [*poof* new-term]
    (println (eval x))))

(defn with-term [term]
  (println x)
  (println (eval x)) ; <== *** FAILS HERE ***
  (func-wbind term))

File b.clj
-----------
(ns b
 (:require [a :refer :all]))

(defn woof-it []
  (with-term "woof")) 

File c.clj
-----------
(ns c
(:require [b :refer :all]))

(defn try-it []
  (woof-it))

使用“c”加载 REPL 并调用 try-it 在未解析的动态变量上失败。

任何帮助将不胜感激。

编辑:以上已修改且可重复的错误。

堆栈跟踪:

ERROR in (endpoint-tests) (Compiler.java:6380)
Default
expected: (map? (endpoint-abstractions ep-any "www.yahoo.com"))
  actual: clojure.lang.Compiler$CompilerException: java.lang.RuntimeException: Unable to resolve symbol: *ph* in this context, compiling:(gl_ep/epref_tests.clj:17:1)
 at clojure.lang.Compiler.analyze (Compiler.java:6380)
    clojure.lang.Compiler.analyze (Compiler.java:6322)
    clojure.lang.Compiler$HostExpr$Parser.parse (Compiler.java:948)
    clojure.lang.Compiler.analyzeSeq (Compiler.java:6560)
    clojure.lang.Compiler.analyze (Compiler.java:6361)
    clojure.lang.Compiler.analyze (Compiler.java:6322)
    clojure.lang.Compiler.analyzeSeq (Compiler.java:6555)
    clojure.lang.Compiler.analyze (Compiler.java:6361)
    clojure.lang.Compiler.analyze (Compiler.java:6322)
    clojure.lang.Compiler$BodyExpr$Parser.parse (Compiler.java:5708)
    clojure.lang.Compiler$FnMethod.parse (Compiler.java:5139)
    clojure.lang.Compiler$FnExpr.parse (Compiler.java:3751)
    clojure.lang.Compiler.analyzeSeq (Compiler.java:6558)
    clojure.lang.Compiler.analyze (Compiler.java:6361)
    clojure.lang.Compiler.eval (Compiler.java:6616)

    clojure.lang.Compiler.eval (Compiler.java:6582)
    clojure.core$eval.invoke (core.clj:2852)
    gl_ep.html_extract$glg_hfm_transform$fn__5320$fn__5321.invoke (html_extract.clj:35)
    hickory.select$attr$fn__5193.invoke (select.clj:220)
    clojure.lang.AFn.applyToHelper (AFn.java:161)
    clojure.lang.AFn.applyTo (AFn.java:151)
    clojure.lang.AFunction$1.doInvoke (AFunction.java:29)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    hickory.select$ordered_adjacent$fn__5271.invoke (select.clj:481)
    hickory.select$select_next_loc.invoke (select.clj:134)
    hickory.select$select_next_loc.invoke (select.clj:129)
    hickory.select$select_next_loc.invoke (select.clj:127)
    hickory.select$select_locs.invoke (select.clj:143)
    hickory.select$select.invoke (select.clj:154)
    gl_ep.html_extract$hickory_get.invoke (html_extract.clj:66)
    gl_ep.html_extract$mapglg$fn__5363.invoke (html_extract.clj:76)
    clojure.core$map$fn__4207.invoke (core.clj:2485)
    clojure.lang.LazySeq.sval (LazySeq.java:42)

    clojure.lang.LazySeq.seq (LazySeq.java:60)
    clojure.lang.RT.seq (RT.java:484)
    clojure.core$seq.invoke (core.clj:133)
    clojure.core$map$fn__4207.invoke (core.clj:2479)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:60)
    clojure.lang.RT.seq (RT.java:484)
    clojure.core$seq.invoke (core.clj:133)
    clojure.core$apply.invoke (core.clj:617)
    gl_ep.html_extract$mapglg.invoke (html_extract.clj:73)
    gl_ep.html_extract$extract.invoke (html_extract.clj:87)
    gl_ep.endpoint$abstractions.doInvoke (endpoint.clj:59)
    clojure.lang.RestFn.invoke (RestFn.java:423)
    gl_ep.endpoint$endpoint_abstractions.doInvoke (endpoint.clj:68)
    clojure.lang.RestFn.invoke (RestFn.java:423)
    gl_ep.epref_tests$fn__8816$fn__8817.invoke (epref_tests.clj:10)
    gl_ep.epref_tests/fn (epref_tests.clj:10)
    clojure.test$test_var$fn__7145.invoke (test.clj:701)
    clojure.test$test_var.invoke (test.clj:701)
    clojure.test$test_all_vars$fn__7149$fn__7156.invoke (test.clj:717)

    clojure.test$default_fixture.invoke (test.clj:671)
    clojure.test$test_all_vars$fn__7149.invoke (test.clj:717)
    clojure.test$default_fixture.invoke (test.clj:671)
    clojure.test$test_all_vars.invoke (test.clj:713)
    clojure.test$test_ns.invoke (test.clj:736)
    clojure.core$map$fn__4207.invoke (core.clj:2487)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:60)
    clojure.lang.Cons.next (Cons.java:39)
    clojure.lang.RT.boundedLength (RT.java:1654)
    clojure.lang.RestFn.applyTo (RestFn.java:130)
    clojure.core$apply.invoke (core.clj:619)
    clojure.test$run_tests.doInvoke (test.clj:751)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    clojure.test$run_tests.invoke (test.clj:749)

最佳答案

当您评估表单时,该表单中的不合格符号将在当前命名空间(由clojure.core/*ns*定义)中解析,位于运行时不是编译对eval的调用的命名空间。因此符号 *poof* 在 REPL 命名空间中被解析。这在命名空间 b 中有效,因为您在需要 a 时执行了 :refer :all,从而创建了 a/* 的本地别名b 中的 poof*c 中不存在这样的别名,因此解析符号失败。

有几个选项可以解决这个问题。您可以更改 x 的声明以使用命名空间限定的符号:

(def x [1 'a/*poof* 3])`

或者,您可以在 *ns* 到命名空间 a 的绑定(bind)中调用 eval

(def x [1 '*poof* 3])

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

然后将对 eval 的调用替换为对 local-eval 的调用。

请参阅Clojure documentation有关评估期间如何解析符号的更详细说明。

关于clojure - 动态变量、绑定(bind)、命名空间可见性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22787516/

相关文章:

clojure - 定义简化的 arity 偏函数

clojure - 如何将 Leiningen 模板部署到 Clojars?

Clojure 'if' 从不评估其第三个参数

map - Clojure 基于优先级逻辑从 map 中提取值(value)

clojure - Clojure 中的结构共享

java - 在 Eclipse 中导出单个 .jar 时避免重复库 .jars

clojure - 使用 environ 访问 leiningen project.clj 中的环境变量时出错

在 Clojure 中解析具有混合类型的文件行

swing - 使用跷跷板启用全屏?

java - Clojure - 找不到匹配的方法