Заставьте класс Java работать как последовательность в Clojure

Я использую класс Java, который представляет последовательность результатов (что-то вроде вектора Clojure).

Я хотел бы использовать этот класс с типичными функциями последовательности Clojure (т.е. я хочу, чтобы класс вел себя так, как если бы он поддерживал абстракцию последовательности), однако я не могу изменить класс, поэтому не могу сделать он реализует clojure.lang.Seqable или аналогичный. Кроме того, досадно, что класс не реализует java.util.Collection или java.lang.Iterable.

Я вижу несколько вариантов:

  • Используйте iterator-seq для (существующего) итератора объекта.
  • Оберните объект в другой класс, который реализует java.util.Collection/clojure.lang.Sequable
  • Создайте функцию, которая создает вектор или последовательность Clojure, запрашивая Object

Есть ли другие варианты? Каков наилучший подход?


person mikera    schedule 19.10.2012    source источник
comment
iterator-seq кажется, что все в порядке, внутри он делает то же самое, что и ваш второй пункт об обертывании объекта   -  person Ankur    schedule 19.10.2012


Ответы (3)


Самым быстрым и простым было бы использовать iterator-seq.

Возникает вопрос: почему ядро ​​Clojure не предоставляет протокол, подобный SeqSource, который будет вызываться seq. Затем нестандартные коллекции могут быть «расширены» для предоставления последовательности, подобно тому, как InternalReduce работает для reduce.

person M Smith    schedule 19.10.2012
comment
Поскольку seq (а) используется компилятором и, следовательно, должен быть дружественным к Java (т. е. интерфейсом), а также (б) вызываться очень, очень часто, поэтому он должен быть максимально быстрым — протоколы быстрее чем много чего, но не так быстро, как простая диспетчеризация интерфейса. - person amalloy; 19.10.2012
comment
@amalloy, тогда, возможно, вместо этого будет функция to-seq - person M Smith; 19.10.2012
comment
Кроме того, досадно, что класс не реализует java.util.Collection или java.lang.Iterable. - person noahlz; 19.10.2012
comment
@noahz Но, исходя из исходного вопроса, итератор объекта (существующий) подразумевает, что итератор доступен. Учитывая, что это кажется излишним для создания прокси. Если бы не итератор, то, конечно, был бы возможен какой-то другой метод. - person M Smith; 19.10.2012
comment
Добавление функции с именем to-seq, которая делает то же самое, что и seq, вообще не решает никаких проблем. Он по-прежнему должен быть доступен для компилятора, чего, конечно же, нет в функциях clojure. - person amalloy; 19.10.2012
comment
@amalloy - Я должен был сказать, что протокол SeqSource имеет одну функцию, to-seq, которую затем можно реализовать в любом произвольном классе, что позволяет любому классу участвовать в парадигме seq. - person M Smith; 21.10.2012

Используйте proxy, чтобы расширить класс и реализовать ISeq

person noahlz    schedule 19.10.2012

Моим первым шагом будет создание ленивой последовательности этого объекта:

(defn sequify [obj]
  (letfn [(inner [idx] 
                 (when (< idx (.size obj))
                          (cons (.get obj idx)
                                (lazy-seq 
                                  (inner (inc idx))))))]
    (inner 0)))

Просто замените .size и .get соответствующими методами.

Написание оболочки может быть более подходящим, если вы хотите повысить производительность по сравнению с решением lazy-seq.

person Ivan Koblik    schedule 19.10.2012