Можно ли определить макрос: что-нибудь еще для отправки по функциям? - PullRequest
0 голосов
/ 11 июня 2018

Я не знаю, как правильно назвать свою проблему, так как я не знаю, как даже начать думать об этом, поэтому я изложу проблему.Представьте, что у меня есть несколько статических методов объекта 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))

Я не знаю, можно ли вызвать "универсальный" статический метод для начинающихдаже если это довольно распространенный вариант использования и не нашел никакого ответа.Я подозреваю, что это не так, потому что ввод "Transforms / floor" в repl рассматривает его как статическое поле, а не как метод, но я не уверен.

1 Ответ

0 голосов
/ 11 июня 2018

Вы можете написать макрос, который расширяется до определения функции, содержащего повторяющийся код:

(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.

...