是否可以定义一个宏:在函数上发送的其他东西?

时间:2018-06-11 16:07:47

标签: clojure static-methods

我不知道如何真正命名我的问题,因为我不知道如何开始考虑这个,所以我会说明问题。 想象一下,我有几个使用相同语法的Java对象静态方法,例如:

https://github.com/deeplearning4j/nd4j/blob/master/nd4j-backends/nd4j-api-parent/nd4j-api/src/main/java/org/nd4j/linalg/ops/transforms/Transforms.java

/**
 * Floor function
 *
 * @param ndArray
 * @return
 */
public static INDArray floor(INDArray ndArray, boolean dup) {
    return exec(dup ? new Floor(ndArray.dup()) : new Floor(ndArray));

}

/**
 * Signum function of this ndarray
 *
 * @param toSign
 * @return
 */
public static INDArray sign(INDArray toSign, boolean dup) {
    return exec(dup ? new Sign(toSign, toSign.dup()) : new Sign(toSign));
}

所以这是一个示例虚拟包装器:

(defn floor
 ^INDArray
  [^INDArray a ^boolean dup]
  (Transforms/floor a dup))

(defn sign
 ^INDArray
  [^INDArray a ^boolean dup]
  (Transforms/sign a dup))

这里的问题是你浪费时间编写具有相同模板的函数,这是第一次没问题......但是想象一下你想要在更改/破坏代码/性能调整/其他情况下更新所有这些函数。
我搜索了这个问题,却一无所获。理想的情况是(一个宏?),如:

(defoperator floor Transforms/floor)

或者

(def floor (->operator Transforms/floor))

我不知道是否可以为初学者调用“通用”静态方法,即使它是一个非常常见的用例并且没有找到任何答案。 我怀疑情况并非如此,因为在repl中键入“Transforms / floor”会将其视为静态字段而不是方法,但我不确定。

1 个答案:

答案 0 :(得分:4)

您可以编写一个扩展为包含重复代码的函数定义的宏:

(defmacro defoperator [op]
  `(defn ~op ; Create a function with "op" as the name
     ^INDArray
     [^INDArray a#, dup#]
     (. Transforms ~op a# dup#))) ; (. Transforms floor) is the same as (Transforms/floor)

现在调用(defoperator floor)会发出一个类似于:

的函数定义
(defn floor
  ^INDArray
  [^INDArray a, dup]
  (. Transforms floor a dup))

此宏假定静态方法名称与要发出的函数相同。如果您希望它们有可能不同,可以使用备用版本:

(defmacro defoperator [fn-name static-name]
  `(defn ~fn-name
     ^INDArray
     [^INDArray a#, dup#]
     (. Transforms ~static-name a# dup#)))

注意,我摆脱了你的^boolean提示。您无法提示布尔基元。我不确定您使用的是哪种版本的Clojure,但这在1.8.0中无效。