clojure - 是否可以定义一个宏:在函数上调度其他任何东西?
问题描述
我不知道如何真正命名我的问题,因为我什至不知道如何开始考虑这个问题,所以我会陈述这个问题。想象一下,我有几个使用相同语法的 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”会将其视为静态字段而不是方法,但我不确定。
解决方案
您可以编写一个扩展为包含重复代码的函数定义的宏:
(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 中不起作用。
推荐阅读
- angular - 在 Angular 中使用替代类提供程序时如何使服务类型化
- python - 无法通过命令提示符运行 Python 文件,文件未定义错误
- rest - Bing Maps REST Service Toolkit not working
- python - Python absolute value
- jquery - How to handle change event of dropdownlist in mvc4?
- python - 在终端上使用时找不到 conda 和 pip 命令
- xml - XML 解析错误:SVG 中未关闭的 CDATA 部分
- python - Python,列出范围内的条件
- javascript - 未捕获的类型错误:addresses.forEach 不是函数
- ios - 在 Swift 4 中使用 UISwitch 启用和禁用位置