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

查看:102
本文介绍了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)

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屋!

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