代码之家  ›  专栏  ›  技术社区  ›  Joseph Yourine

是否可以定义一个宏:在函数上分派任何其他内容?

  •  1
  • Joseph Yourine  · 技术社区  · 7 年前

    我不知道如何说出我的问题,因为我甚至不知道如何开始思考这个问题,所以我会陈述这个问题。 想象一下,我有几种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 回复  |  直到 7 年前
        1
  •  4
  •   Carcigenicate    7 年前

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

    (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中不起作用。