首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在Clojure中,如何定义由字符串命名的变量?

在Clojure中,如何定义由字符串命名的变量?
EN

Stack Overflow用户
提问于 2010-03-21 18:46:48
回答 4查看 6.8K关注 0票数 19

给定变量的名称列表,我想将这些变量设置为一个表达式。

我试过这个:

代码语言:javascript
复制
(doall (for [x ["a" "b" "c"]] (def (symbol x) 666)))

...but这会产生错误

java.lang.Exception:定义的第一个参数必须是符号

有人能告诉我完成这件事的正确方法吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-03-28 03:42:35

Clojure的"intern“函数就是为了这个目的:

代码语言:javascript
复制
(doseq [x ["a" "b" "c"]]
  (intern *ns* (symbol x) 666))
票数 36
EN

Stack Overflow用户

发布于 2010-03-21 20:04:30

代码语言:javascript
复制
(doall (for [x ["a" "b" "c"]] (eval `(def ~(symbol x) 666))))

对您的评论的回应:

这里没有涉及宏。eval是一个函数,它接受一个列表,并以代码的形式返回执行该列表的结果。`和~是创建部分引用列表的快捷方式。

`表示以下列表的内容应加引号,除非前面有~

~下面的列表是应该执行的函数调用,而不是引号。

所以(def ~(symbol x) 666)is the list containing the symboldef, followed by the result of executingsymbol xfollowed by the number of the beast. I could as well have written(is the list containing the symbol (list 'def (symbol x) 666))`也可以达到同样的效果。

票数 13
EN

Stack Overflow用户

发布于 2010-03-22 01:12:43

更新以考虑斯图亚特·塞拉的评论(提到clojure.core/intern__)。

在这里使用eval是很好的,但是知道它不是必需的可能很有趣,不管Vars是否已知已经存在。事实上,如果已知它们存在,那么我认为下面的alter-var-root解决方案更简洁;如果它们可能不存在,那么我不会坚持我的替代方案更简洁,但它似乎有利于最短的代码(如果我们忽略了函数定义的三行开销),所以我将其张贴出来供您考虑。

如果已知Var存在:

代码语言:javascript
复制
(alter-var-root (resolve (symbol "foo")) (constantly new-value))

所以你可以这样做

代码语言:javascript
复制
(dorun
  (map #(-> %1 symbol resolve (alter-var-root %2))
       ["x" "y" "z"]
       [value-for-x value-for-y value-for z]))

(如果要对所有Var使用相同的值,则可以使用(repeat value)作为最后一个参数进行映射,或者直接将其放入匿名函数中。)

如果可能需要创建Vars,那么您实际上可以编写一个函数来完成这项工作(再次声明,我不一定声称它比eval更干净,但不管怎样--只是出于兴趣):

代码语言:javascript
复制
(defn create-var
  ;; I used clojure.lang.Var/intern in the original answer,
  ;; but as Stuart Sierra has pointed out in a comment,
  ;; a Clojure built-in is available to accomplish the same
  ;; thing
  ([sym] (intern *ns* sym))
  ([sym val] (intern *ns* sym val)))

请注意,如果一个Var已经在给定的名称空间中使用了给定的名称,那么在单参数的情况下不会改变任何东西,或者在两个参数的情况下只是将Var重置为给定的新值。这样,您就可以像这样解决原始问题:

代码语言:javascript
复制
(dorun (map #(create-var (symbol %) 666) ["x" "y" "z"]))

一些额外的例子:

代码语言:javascript
复制
user> (create-var 'bar (fn [_] :bar))
#'user/bar
user> (bar :foo)
:bar

user> (create-var 'baz)
#'user/baz
user> baz
; Evaluation aborted. ; java.lang.IllegalStateException:
                      ;   Var user/baz is unbound.
                      ; It does exist, though!

;; if you really wanted to do things like this, you'd
;; actually use the clojure.contrib.with-ns/with-ns macro
user> (binding [*ns* (the-ns 'quux)]
        (create-var 'foobar 5))
#'quux/foobar
user> quux/foobar
5
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2486752

复制
相关文章

相似问题

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