2012-02-10 9 views
12

Używam biblioteki Sesame do uruchamiania zapytań SPARQL przez potrójny magazyn w pamięci.Jak zmienić obiekt podobny do iteratora java do sekwencji clojure

Używam Clojure, aby to osiągnąć.

Wynik zapytania jest niestandardowym obiektem podobnym do Iteratora [1], więc clojure seq nie działa na nim po wyjęciu z pudełka.

Jaki jest najbardziej elegancki sposób przekształcenia niestandardowego obiektu podobnego do Iteratora w sekwencję clojure?

Najbardziej oczywistym i głupim pomysłem, który przyszedł mi do głowy, jest zapętlenie i zbudowanie wektora clojure, ale jestem pewien, że jest bardziej eleganckie podejście do tego problemu.

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

Odpowiedz

8

The testowana wersja:

(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

To (reifikacja Iterable zamiast Iterator) to jedno podejście; kolejnym jest reifikacja Iteratora, a następnie zawijanie go za pomocą ['iterator-seq'] (http://clojuredocs.org/clojure_core/clojure.core/iterator-seq). – amalloy

+0

Miło, dobrze wiedzieć! – laczoka

5

Jak o owijania przedmiotu iteracyjnej jak w obiekcie, który faktycznie realizuje interfejs Iterator? Coś jak poniżej (nie sprawdzone)

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

O ile mogę powiedzieć, jedyną zaletą (jeśli chcesz to tak nazwać) interfejsu Iteration nad standardowym Iterator interfejsu jest to, że pozwala zadeklarować sprawdzone wyjątki, które i tak nie są używane w Clojure.

[Update: Poprawiono kod używać iterator-seq zamiast seq, jak sugeruje @amalloy w komentarzu do innej odpowiedzi.]

+0

Dzięki. Niezupełnie, ale wskazał mi właściwy kierunek i pomógł mi nauczyć się praktycznego używania * reify *. – laczoka

+0

Mam już przetestowaną poprawną wersję, po prostu nie mogę odpowiedzieć na własne pytanie z powodu ograniczeń związanych z reputacją. :) – laczoka

1

Czysta funkcjonalny iterable-to- Kod leniwy-sekwencja java iterable i Iterator

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

przypadku niestandardowych iteratorów zastąpić .iterator, .hasNext i połączeń .next.

Zaletą jest to, że jest czysto funkcjonalny, ponieważ wymaga argumentów jako możliwych do sprawdzenia. Inne opublikowane rozwiązania przyjmują argument iteratora, który można zmienić, aby funkcja mogła zwracać inną sekwencję w zależności od wewnętrznego stanu iteratora, co narusza referential transparency. Ta funkcja jest również ekstrawagancka z powodu jej lenistwa.

1

Dlaczego nie dać clojure.core/iterator-seq spróbować?

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. 

Jak widać w docstring powyżej, użytkownik może nawet nie trzeba używać iterator-seq wyraźnie. Czy po prostu spróbuj traktować swój iterator Java jako sekwencję w REPL?

+0

To nie działa, ponieważ iterator-seq jawnie działa tylko z java.util.Iterator, podczas gdy opisany tutaj obiekt to info.aduna.iteration.Iteration. Użycie iteratora-seq prowadzi do wyjątku ClassCastException. – PaulaG

Powiązane problemy