Есть ли в Clojure функция apply для функций Java? - PullRequest
16 голосов
/ 29 декабря 2011
 user=> (Integer/rotateRight 0 0)
 0

 user=>  (apply Integer/rotateRight [0 0])
 CompilerException java.lang.RuntimeException: Unable to find static field: 
   rotateRight in class java.lang.Integer, compiling:(NO_SOURCE_PATH:172)

Есть ли способ подать заявку на Java-функции в Clojure? Если нет, то как я мог бы написать макрос или функцию, которая бы поддерживала это?

Ответы [ 3 ]

17 голосов
/ 29 декабря 2011

Самая простая вещь, которую я могу придумать, это обернуть ее в функцию, но я не совсем уверен, является ли это лучшим / наиболее идиоматическим способом:

user> (apply (fn [a b] (Integer/rotateRight a b)) [0 0])
0

Или, немного короче, но эквивалентно:

user> (apply #(Integer/rotateRight %1 %2) [0 0])
0

В качестве альтернативы, вы можете создать подходящую функцию-обертку для вызова метода java:

(defn rotate-right [a b]
  (Integer/rotateRight a b))

Вы бы использовали это так:

user> (apply rotate-right [0 0])
0

edit : просто для удовольствия, вдохновленный комментарием iradik об эффективности, сравнением времени между тремя различными способами вызова этого метода:

;; direct method call (x 1 million)
user> (time (dorun (repeatedly 1E6 #(Integer/rotateRight 2 3))))
"Elapsed time: 441.326 msecs"
nil

;; method call inside function (x 1 million)
user> (time (dorun (repeatedly 1E6 #((fn [a b] (Integer/rotateRight a b)) 2 3))))
"Elapsed time: 451.749 msecs"
nil

;; method call in function using apply (x 1 million)
user> (time (dorun (repeatedly 1E6 #(apply (fn [a b] (Integer/rotateRight a b)) [2 3]))))
"Elapsed time: 609.556 msecs"
nil
4 голосов
/ 29 декабря 2011

Пара моментов, которые здесь, хотя и не являются прямым ответом, актуальны.

Во-первых, у Java нет функций.Он имеет только методы экземпляра или статические методы.Это может показаться педантичным различием, но оно действительно имеет значение (как показано в некоторых других примерах, когда для статического вызова и вызова экземпляра требуются разные формы).

Во-вторых, несоответствие импеданса между системами типоввступает в игру.Чтобы Java имела полноценную поддержку FP на Java-языке, она должна быть статически типизирована.Оказывается, это довольно сложно сделать по-настоящему удовлетворительным образом (см. Обсуждение в списке рассылки lambda-dev для подробностей о подходе, который используется и появится в Java 8).

Из этихВ двух моментах мы видим, что из Clojure лучшее, что мы действительно можем сделать, - это поддержать подход «все ставки выключены» для вызова методов Java через # () или аналогичный метод.Clojure будет выбирать только формы для вызова, основываясь на арности аргумента, поэтому могут потребоваться какие-то подсказки типов или приведение типов, чтобы гарантировать, что вызывается правильный перегруженный метод Java.

Что еще более важно, конечно, если пользователь передает аргумент типа, который Java не ожидает или не может обработать, это может быть невозможно обнаружить до времени выполнения.

0 голосов
/ 29 декабря 2011

Я написал несколько макросов для этого, вдохновившись ответом Герталота.Появляется для компиляции с эквивалентным нормальным кодом.Бенчмарк был идентичным.Любопытно, что вы думаете.

(defmacro java-new-apply 
   ([klass] `(new ~klass))
   ([klass args] `(new ~klass ~@(map eval args))))

(defmacro java-static-apply 
   ([f] f)
   ([f args] `(~f ~@(map eval args))))

(defmacro java-method-apply 
   ([method obj] method obj) 
   ([method obj args] `(~method ~obj ~@(map eval args))))

;; get date for Jan 1 1969
(import java.util.Date)
(java-new-apply Date [69 1 1])
(macroexpand '(java-new-apply Date [69 1 1]))
(new Date 69 1 1)

(java-static-apply Integer/rotateRight [2 3])
(macroexpand '(java-static-apply Integer/rotateRight [2 3]))
(. Integer rotateRight 2 3)

(java-method-apply .substring "hello world!" [6 11])
(macroexpand '(java-method-apply .substring "hello world!" [6 11]))
(. "hello world!" substring 6 11)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...