与eval
一起使用时,带闭包的函数似乎会中断。
(eval {:fn (let [x "foo"] (fn [] "x"))})
;=> {:fn #<user$eval14716$fn__14717 user$eval14716$fn__14717@1ddd735>}
(eval {:fn (let [x "foo"] (fn [] x))})
;=> IllegalArgumentException No matching ctor found for class user$eval14740$fn__14741
; clojure.lang.Reflector.invokeConstructor (Reflector.java:166)
我对Clojure(或封闭)知之甚少,不知道这是一个错误还是故意不被允许的东西 - 有人可以对此有所了解吗?
编辑:为了清楚起见,我正在谈论eval
处理函数对象的方式。 AFAIK eval
实际上设计用于处理java对象,包括函数;在clojure网站上给出的示例 - (eval (list + 1 2 3))
- 将函数对象传递给eval
。
答案 0 :(得分:2)
Cloure的eval
并不完全支持函数对象。它不一定是导致问题的闭包。
例如,这在Clojure 1.0.0 :
中无效(eval {:fn (fn [x] x)})
但是这样做了:
(eval (fn [x] x))
第一个例子得到修复。以下也有效:
(eval (let [x "foo"] (fn [] x)))
但以下情况仍无效:
(eval {:fn (let [x "foo"] (fn [] x))})
我无法将其归结为编译器中的单行,但它是关于eval
在不同上下文中如何处理文字对象(clojure.lang.Compiler $ ObjExpr)的原因:例如:在表达式的“顶部”与另一个数据结构内部。
一般来说,我认为,你不能依赖于能够在Clojure中使用eval
函数对象,无论它们是否是闭包。它恰好适用于一些简单的例子,主要是为了简化(eval (list + 1 2))
之类的解释。宏应始终将文字源代码作为数据结构返回,而不是编译函数。
答案 1 :(得分:1)
尝试引用你的参数eval:
(eval '{:fn (let [x "foo"] (fn [] x))})
;=> {:fn #<user$eval345$fn__346 user$eval345$fn__346@17b6dd83>}
((:fn *1))
;=> "foo"
答案 2 :(得分:1)
这不是错误。具有“结束”的(eval (list + 1 2 3))
相当于(eval (list fn [] "foo"))
,不是 (eval (fn [] "foo"))
。
而且(eval (list fn [] "foo")) => Can't take value of a macro: #'clojure.core/fn
,再次表明你不应该做那样的事情(而且无论如何也没有必要)。