2012-02-10 12 views
12

Estoy usando la biblioteca Sesame para ejecutar consultas SPARQL en una tienda triple en memoria.Cómo convertir un objeto similar a un iterador java en una secuencia de clojure

Estoy usando Clojure para lograrlo.

El resultado de una consulta es un objeto Iterator-like [1] personalizado, por lo que clojure seq no funciona en él de la caja.

¿Cuál es la forma más elegante de convertir un objeto personalizado como un iterador de Java en una secuencia de clojure?

La idea más obvia y tonta que se me viene a la mente es recorrerla y crear un vector clojure, pero estoy seguro de que hay un enfoque más elegante para este problema.

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

Respuesta

8

La versión probada:

(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

Esto (que reifica Iterable en lugar de Iterador) es un enfoque; otra es reificar Iterator y luego envolverlo con ['iterator-seq'] (http://clojuredocs.org/clojure_core/clojure.core/iterator-seq). – amalloy

+0

¡Agradable, es bueno saberlo! – laczoka

5

¿Qué hay de envolver el objeto iterador-como en un objeto que implementa la interfaz de realidad Iterator? Algo como lo siguiente (no probado):

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

Por lo que yo puedo decir, la única ventaja (si se quiere llamar así) de la interfaz Iteration través de la interfaz estándar de Iterator es que permite declarar comprobadas excepciones, que no se utilizan en Clojure de todos modos.

[Actualización: Se ha corregido código usar iterator-seq en lugar de seq, según lo sugerido por @amalloy en un comentario en otra respuesta.]

+0

Gracias. No del todo, pero me indicó la dirección correcta y me ayudó a aprender sobre el uso práctico de * reify *. – laczoka

+0

Ya obtuve una versión correcta probada, pero aún no puedo auto-responder debido a alguna restricción de reputación. :) – laczoka

1

puro funcional iterables-a- código perezoso-secuencia para java Iterable y iterador

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

para iteradores personalizados reemplazar .iterator, .hasNext y llamadas .Next.

La ventaja es que es puramente funcional, ya que toma iterable como argumento. Otras soluciones publicadas toman el argumento iterador, que es mutable, por lo que la función puede devolver una secuencia diferente dependiendo del estado del iterador interno, lo que infringe referential transparency. La función también es extravagante sobre su pereza.

1

¿Por qué no probar 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. 

Como se puede ver en la cadena de documentación anterior, es posible que ni siquiera necesidad de utilizar iterator-seq explícitamente. ¿Intentó tratar su iterador de Java como una secuencia en el REPL?

+0

Esto no funciona, ya que iterator-seq explícitamente solo funciona con java.util.Iterator, mientras que el objeto aquí descrito es info.aduna.iteration.Iteration. El uso de iterator-seq conduce a una ClassCastException. – PaulaG

Cuestiones relacionadas