首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Clojure中的动态let?

Clojure中的动态let?
EN

Stack Overflow用户
提问于 2012-01-20 16:10:36
回答 3查看 869关注 0票数 4

我在REPL中发生了以下情况:

代码语言:javascript
复制
mathematics.core> (let [zebra 1] (resolve 'zebra))
nil
mathematics.core> (def zebra 1)
#'mathematics.core/zebra
mathematics.core> (let [zebra 2] (when (resolve 'zebra) (eval 'zebra))) 
1

基本上,我希望使用类似于let表单的东西将值动态绑定到变量,并使该表单中的函数能够访问变量绑定到的值。

代码语言:javascript
复制
mathematics.core> (def ^:dynamic zebra 1)
#'mathematics.core/zebra   
mathematics.core> (binding [zebra 2] (when (resolve 'zebra) (eval 'zebra))) 
2

binding似乎做了我想要的把戏,但是AFAIK它首先需要用:dynamic元数据定义一个变量。我希望能够动态地使用以前从未定义过的变量,并让形式中的表达式能够访问该变量,就像它是实际定义的一样。

为了说明,我想要这样的东西:

代码语言:javascript
复制
mathematics.core> (let-dynamic [undefined-variable 1]
                    (when (resolve 'undefined-variable) (eval 'unresolved-variable)))
1

有什么简单的方法可以做到这一点吗?或者是一种使用宏来完成此任务的方法?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-01-20 18:43:17

这不会很好地工作。如果没有定义这个符号,那么Clojure编译器就不能编译任何使用它的代码。你也许能够在需要的时候使用一些延迟调用def的宏,但这将是一些非常糟糕的代码.

我建议只使用绑定,并提前定义您的var。你应该能够以这种方式编写你的代码。

我认为“即时”定义变量不是一个好主意。我认为你不应该真的需要这个--如果你在代码中使用变量,那么只需预先为你使用的每个变量做一个(def ^:dynamic ...)就足够简单了。

票数 4
EN

Stack Overflow用户

发布于 2012-01-20 17:38:49

我希望能够动态地使用以前从未定义过的变量,并让形式的表达式能够访问该变量,就像它是实际定义的一样。

在我看来,这对于clojure的vars或let-bound值来说并不是一个很好的匹配,如果您无论如何都是在动态生成和求值整个表单,为什么不使用一个简单的映射来存储符号->值映射,并用映射查找替换整个解析/求值方案?这样,您就可以动态生成任意符号,而不会出现任何晦涩难懂的名称空间技巧,这些技巧可能会以难以找到的方式破坏您的代码:

代码语言:javascript
复制
(let [my-resolve {'zebra 1}]
   (println "zebra is " (my-resolve 'zebra)))
票数 3
EN

Stack Overflow用户

发布于 2012-01-20 19:18:57

虽然这不是一个完整的解决方案,但这里是一个尝试:

代码语言:javascript
复制
(defmacro let-dynamic 
      ([[sym val & more] & body]
       `(do (when (not (:dynamic (meta (resolve '~sym))))
              (def ~(with-meta sym {:dynamic true}) ~sym))
            (binding [~sym ~val] 
              ~@(if (empty? more)
                    body
                    `((let-dynamic ~more ~@body)))))))

一个小测试:

代码语言:javascript
复制
blub> (def ^:dynamic already-dynamic 'dynamic)
#'blub/already-dynamic
blub> (def not-dynamic 'not-dynamic)
#'blub/not-dynamic
blub> (let-dynamic [already-dynamic 2] already-dynamic)
2
blub> (let-dynamic [not-dynamic 2] not-dynamic)
2
blub> (let-dynamic [not-dynamic-and-not-defined 2] not-dynamic-and-not-defined)
2
blub> 

这有几个问题:

由于某种原因,将多个符号-值对传递给-

  1. 不能像预期的那样工作。它们只会在第二次调用LET-DYNAMIC时被绑定。这可能可以通过更改宏来将所有符号-值对传递到第一个绑定形式中来解决,而不是像我在上面的代码中所做的那样递归地构建绑定,以前不存在的
  2. 变量将不会被清除。你可以通过保存定义了什么和没有定义什么的映射来修复这个问题。
  3. 我不知道这在多线程环境中会发生什么。你得自己去评估。
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8938398

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档