Clojure中的不一致:宏中的函数和IllegalArgumentException [英] Inconsistency in Clojure: functions in macros and IllegalArgumentException
问题描述
以下两个在宏中使用函数的示例导致无错误的评估。
Two following examples of using a function in a macro result in evaluations without errors.
(defmacro works []
(let [f (fn [] 1)]
`(~f)))
(works)
;; => 1
(defn my-nullary-fn []
(fn [] 2))
(defmacro also-works []
(let [f (my-nullary-fn)]
`(~f)))
(also-works)
;; => 2
但是,
(defmacro does-not-work []
(let [f (constantly 3)]
`(~f)))
(does-not-work)
throws
java.lang.IllegalArgumentException: No matching ctor found
for class clojure.core$constantly$fn__4051
同样,
(defn my-unary-fn [x]
(fn [] x))
(defmacro also-does-not-work []
(let [f (my-unary-fn 4)]
`(~f)))
(also-does-not-work)
throws
java.lang.IllegalArgumentException No matching ctor found
for class user$my_other_fn$fn__12802
可能是什么原因?由 fn
, my-nullary-fn
,不断返回的函数对象之间有差异
和 my-unary-fn
?
What might be the reason? Is there a difference between function objects returned by fn
, my-nullary-fn
, constantly
and my-unary-fn
?
我正在运行Clojure 1.5.1 。
I'm running Clojure 1.5.1.
CLJ-946 可能相关。
推荐答案
查看 clojure.lang.Compiler.ObjExpr#emitValue()
。直接出现在代码中的任何实例对象(或生成的代码,在宏扩展结果的情况下)必须:
Take a look at clojure.lang.Compiler.ObjExpr#emitValue()
. Any instance objects which appear directly in code (or generated code, in the case of macro-expansion results) must either:
- 类型编译器知道如何实例化或发出引用;或
- 为它们的类型定义了
print-dup
,在这种情况下,编译器通过读取器往返发送对象实例化。
- Be of a type compiler knows how to instantiate or emit a reference to; or
- Have
print-dup
defined for their type, in which case the compiler emits object instantiation via round-tripping through the reader.
函数对象有一个 print-dup
-eval形式,它只调用函数类构造函数的0参数版本:
Function objects do have a print-dup
implementation, but it constructs read-eval forms which only call the 0-argument version of the function class constructor:
(print-dup (fn [] 1) *out*)
;; #=(user$eval24491$fn__24492. )
(let [x 1] (print-dup (fn [] x) *out*))
;; #=(user$eval24497$fn__24498. )
Clojure闭包是通过函数类实现的,闭合变量值作为构造函数参数。因此:
Clojure closures are implemented via function-classes which accept their closed-over variable values as constructor arguments. Hence:
(let [f (fn [] 1)] (eval `(~f)))
;; 1
(let [x 1, f (fn [] x)] (eval `(~f)))
;; IllegalArgumentException No matching ctor found ...
所以现在你知道,知道为什么要避免直接插入函数对象转换为生成的代码,即使它工作。
So now you know, and know why to avoid directly inserting function objects into generated code, even when it "works."
这篇关于Clojure中的不一致:宏中的函数和IllegalArgumentException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!