2

与闭包一起使用时,函数似乎会中断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处理函数对象的方式。AFAIKeval实际上是为处理 java 对象而设计的,包括函数;clojure 网站上给出的示例(eval (list + 1 2 3))- 将函数对象传递到eval.

4

3 回答 3

3

Cloureeval并不完全支持函数对象。甚至不一定是导致问题的闭包。

例如,这在 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))})

我不能将它固定到编译器中的一行,但它是关于如何在不同的上下文中处理文字对象(clojure.lang.Compiler$ObjExpr)eval:例如在表达式的“顶部”与在另一个数据结构中。

一般来说,我认为,eval无论它们是否是闭包,你都不能依赖于能够在 Clojure 中运行对象。它恰好适用于一些简单的示例,主要是为了简化对(eval (list + 1 2)). 宏应始终将文字源代码作为数据结构返回,而不是编译函数。

于 2012-07-02T02:19:02.637 回答
1

尝试将您的论点引用到 eval:

(eval '{:fn (let [x "foo"] (fn [] x))})
;=> {:fn #<user$eval345$fn__346 user$eval345$fn__346@17b6dd83>}
((:fn *1))
;=> "foo"
于 2012-06-25T15:37:44.250 回答
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,再次表明您不应该做那样的事情(无论如何也不需要这样做)。

于 2012-06-26T07:29:08.937 回答