Car*_*icz 18 symbols function clojure
给定变量的名称列表,我想将这些变量设置为表达式.
我试过这个:
(doall (for [x ["a" "b" "c"]] (def (symbol x) 666)))
Run Code Online (Sandbox Code Playgroud)
......但这会产生错误
java.lang.Exception:def的第一个参数必须是Symbol
有谁能告诉我正确的方法,请?
Stu*_*rra 34
Clojure的"实习生"功能就是为了这个目的:
(doseq [x ["a" "b" "c"]]
(intern *ns* (symbol x) 666))
Run Code Online (Sandbox Code Playgroud)
sep*_*p2k 13
(doall (for [x ["a" "b" "c"]] (eval `(def ~(symbol x) 666))))
Run Code Online (Sandbox Code Playgroud)
回应你的评论:
这里没有涉及宏.eval是一个获取列表并将执行该列表的结果作为代码返回的函数.`和〜是创建部分引用列表的快捷方式.
`表示除非前面带有〜,否则应引用以下列表的内容
〜以下列表是一个函数调用,应该执行,而不是引用.
所以``(def~(符号x)666)is the list containing the symboldef , followed by the result of executing符号x followed by the number of the beast. I could as well have written(eval(list'snd(符号x)666))`来实现相同的效果.
更新以考虑Stuart Sierra的评论(提及clojure.core/intern).
eval在这里使用很好,但是可能有趣的是,无论已知Vars是否存在,都没有必要.事实上,如果他们知道存在,那么我认为alter-var-root下面的解决方案更清洁; 如果它们可能不存在,那么我不会坚持我的替代命题更清晰,但似乎是为了最短的代码(如果我们忽略函数定义的三行开销),所以我只是发布它供你考虑.
如果已知Var存在:
(alter-var-root (resolve (symbol "foo")) (constantly new-value))
Run Code Online (Sandbox Code Playgroud)
所以你可以做到
(dorun
(map #(-> %1 symbol resolve (alter-var-root %2))
["x" "y" "z"]
[value-for-x value-for-y value-for z]))
Run Code Online (Sandbox Code Playgroud)
(如果所有Vars都使用相同的值,则可以使用(repeat value)最终参数进行映射或将其放入匿名函数中.)
如果可能需要创建Vars,那么你实际上可以编写一个函数来执行此操作(再一次,我不一定声称这个更干净eval,但无论如何 - 只是为了它的利益):
(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)))
Run Code Online (Sandbox Code Playgroud)
请注意,如果Var已经在给定的命名空间中使用给定的名称进行了实例化,那么这在单个参数的情况下不会改变任何内容,或者只是在两个参数的情况下将Var重置为给定的新值.有了这个,您可以像这样解决原始问题:
(dorun (map #(create-var (symbol %) 666) ["x" "y" "z"]))
Run Code Online (Sandbox Code Playgroud)
一些额外的例子:
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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6359 次 |
| 最近记录: |