Clojure : 类型提示塔

Posted

技术标签:

【中文标题】Clojure : 类型提示塔【英文标题】:Clojure : type hint tower 【发布时间】:2017-07-27 16:07:56 【问题描述】:

我有时会编写 java 方法,特别是对于基元/数组操作,我总是纠结于如何在 Clojure 1.8 下使用类型提示。我看到了一些线程,但考虑到它们已在 2 年多前发布,它们(也许?)已经过时了。

我将举一个基本的例子来说明我的观点(我知道这个例子有点毫无意义)。在这里,我想将两个 double 相加并返回一个 double

这是一个Java方法:

public static double add (double a, double b) 

    return a + b;

然后我想要一个 Clojure 包装器:

版本 1

(defn d+ ^double 
  [^double a ^double b]
  (Doubles/add a b))

第 2 版

(defn d+ ^double 
  [^double a ^double b]
  (Doubles/add ^double a ^double b))

第 3 版

(defn d+ ^double 
  [^double a ^double b]
  (Doubles/add (double a) (double b)))

我不知道在哪里放置类型提示以及如何放置它们。我的印象是(double x) 效率较低,因为它是一个函数(也许我错了?)。 那么在 body 函数内部和外部给出提示有什么区别呢?

或者也许这些提示是不必要的,因为 Java 类中只有一种方法? 我看不到逻辑,所以我通常使用版本 1 或 3(越多越好?)。

请注意,对于此示例,Clojure + 总是更快

【问题讨论】:

*warn-on-reflection* 标志将有助于这种探索。只需将其设置为 true,编译器就会发出无法选择所需方法重载并需要提示的情况。 谢谢我已经测试过了,最后不需要任何提示。你知道为什么这个函数比较慢,因为它只适用于 double 吗?我的直觉是互操作意味着一些隐藏的操作/成本,因此 Java 互操作只有在函数成本高(如大算法)或函数在 Clojure 中不存在时才值得。 @leetwinski 原始类型提示与反射警告无关,它们是针对对象的。原始提示用于避免装箱的性能。更好的是在你的 clojure 文件请求时启用(set! *unchecked-math* :warn-on-boxed) 【参考方案1】:

版本 1 是正确的。它将发出以下字节码:

public final class compile_inspect$d_PLUS_ extends AFunction implements DDD 
    public compile_inspect$d_PLUS_() 
    

    public static double invokeStatic(double a, double var2) 
        return Primitives.add(a, var2);
    

    public Object invoke(Object var1, Object var2) 
        return new Double(invokeStatic(RT.uncheckedDoubleCast((Number)var1), RT.uncheckedDoubleCast((Number)var2)));
    

    public final double invokePrim(double var1, double var3) 
        return invokeStatic(var1, var3);
    

Primitives.add 就像您的 Doubles/add 函数一样。

如果您想要性能并避免拳击,您应该设置:

(set! *unchecked-math* :warn-on-boxed)

同时通过Java interop reference(CTRL+F“原始”)也会有所帮助。

【讨论】:

非常感谢,我也有关于附属问题的答案 ==> “并且数字基元将变成数字,除非它们立即被采用基元的方法使用。”这解释了简单操作的孤立性能有点差,还有一些不可能的任务(使用返回 double/float/etc 的方法扩展接口)

以上是关于Clojure : 类型提示塔的主要内容,如果未能解决你的问题,请参考以下文章

卡在 clojure 中的泛型类类型提示

Clojure 中函数的类型提示

在 Clojure 中类型提示一个 nil 文字

为啥 Clojure 编译器不会为不正确的类型提示抛出错误?

类型提示存储为clojure中的元数据?

尽管在 Clojure 中对 Java 构造函数有类型提示,但仍会出现反射警告