Clojure 中的不一致:宏和 IllegalArgumentException 中的函数 [英] Inconsistency in Clojure: functions in macros and IllegalArgumentException

查看:10
本文介绍了Clojure 中的不一致:宏和 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)

投掷

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)

投掷

java.lang.IllegalArgumentException No matching ctor found
for class user$my_other_fn$fn__12802

可能是什么原因?fnmy-nullary-fnconstantlymy-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 实现,但它构造了 read-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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆