Подтвердить что ты не робот

Как превратить java-итератор-подобный объект в последовательность clojure

Я использую библиотеку Sesame для запуска запросов SPARQL по трем хранилищу в памяти.

Я использую Clojure для достижения этого.

Результат запроса является обычным Iterator-подобным [1] объектом, поэтому Clojure seq не работает на нем из коробки.

Каков самый элегантный способ превратить пользовательский Java-объект Iterator в последовательность Clojure?

Наиболее очевидной и немой идеей, которая мне пришла в голову, является ее надстройка и создание вектора Clojure, но я уверен, что есть более элегантный подход к этой проблеме.

[1] http://www.openrdf.org/doc/sesame2/api/info/aduna/iteration/Iteration.html

4b9b3361

Ответ 1

Тестируемая версия:

(defn iteration->seq [iteration]
 (seq
  (reify java.lang.Iterable 
      (iterator [this] 
         (reify java.util.Iterator
           (hasNext [this] (.hasNext iteration))
           (next [this] (.next iteration))
           (remove [this] (.remove iteration)))))))

Ответ 2

Как обернуть объект, похожий на итератор, в объект, который фактически реализует интерфейс Iterator? Что-то вроде следующего (не проверено):

(defn iteration-seq [iteration]
  (iterator-seq
   (reify java.util.Iterator
     (hasNext [this] (.hasNext iteration))
     (next [this] (.next iteration))
     (remove [this] (.remove iteration)))))

Насколько я могу судить, единственным преимуществом (если вы хотите это назвать) интерфейса Iteration над стандартным интерфейсом Iterator является то, что он позволяет объявлять проверенные исключения, которые не используются в Clojure в любом случае.

[Обновить: исправленный код для использования iterator-seq вместо seq, как это было предложено @amalloy в комментарии к другому ответу.]

Ответ 3

Чистый функциональный код с итерируемой до ленивой последовательности для java Iterable и Iterator

(defn iter-seq
  ([iterable] 
    (iter-seq iterable (.iterator iterable)))
  ([iterable i] 
    (lazy-seq 
      (when (.hasNext i)
        (cons (.next i) (iter-seq iterable i))))))

Для пользовательских итераторов замените .iterator,.hasNext и .next вызовы.

Преимущество состоит в том, что он чисто функциональный, поскольку он принимает итерабельность в качестве аргумента. Другие опубликованные решения принимают аргумент итератора, который изменен, поэтому функция может возвращать другую последовательность в зависимости от внутреннего состояния итератора, что нарушает ссылочную прозрачность. Эта функция также ярка в отношении ее лени.

Ответ 4

Почему бы не дать clojure.core/iterator-seq попробовать?

user=> (doc iterator-seq)
-------------------------
clojure.core/iterator-seq
([iter])
  Returns a seq on a java.util.Iterator. Note that most collections
  providing iterators implement Iterable and thus support seq directly.

Как вы можете видеть в приведенной выше документации, вам может даже не понадобиться явно использовать iterator-seq. Вы просто пытались обработать свой Java-итератор как последовательность в REPL?