2009-10-29 16 views
83

He intentado lo siguiente en Clojure, esperando tener la clase de una secuencia no volvieron perezosos:Cómo convertir secuencia perezoso para no perezoso en Clojure

(.getClass (doall (take 3 (repeatedly rand)))) 

Sin embargo, esto sigue devolviendo clojure.lang.LazySeq. Supongo que doall evalúa la secuencia completa, pero devuelve la secuencia original, ya que aún es útil para la memorización.

Entonces, ¿cuál es el medio idiomáticas de la creación de una secuencia no perezoso de un perezoso?

+0

Me sorprende que nadie haya preguntado por qué le preocupa el tipo real del valor de retorno de 'doall' – tar

+0

Puede convertirlo en un vector:' (vec (tomar 3 (repetidamente rand))) ' – Kris

Respuesta

139

Doall es todo lo que necesita. Solo porque el seq tenga tipo LazySeq no significa que tenga una evaluación pendiente. SEQs perezosos caché de sus resultados, así que todo lo que necesita hacer es caminar por la SEC perezoso una vez (como Doall hace) con el fin de obligar a todo, y por lo tanto hacer que pierdan su-perezoso. ss hace no fuerza de toda la colección para ser evaluados.

+2

I ' ha cambiado esto a la respuesta aceptada. En una nota relacionada, ¿por qué medios puede determinar si un LazySeq ha sido evaluado previamente? –

+10

Creo que acaba de llamar '¿se dio cuenta?'. – toofarsideways

+1

Probablemente debería haber una operación de 'realización' para que coincida con '¿se dio cuenta?'. –

4
(.getClass (into '() (take 3 (repeatedly rand)))) 
+3

Esta es una idea terrible. Revierte la entrada seq. – amalloy

+3

Por supuesto, en este caso invertir la entrada no hace ninguna diferencia, ya que son solo 3 números aleatorios .... :-) – mikera

57

Esto es hasta cierto punto una cuestión de taxonomía. una secuencia perezoso es sólo un tipo de secuencia de como es una lista, vector o un mapa. Así que la respuesta es, por supuesto, "depende de qué tipo de secuencia no perezoso desea obtener:
serie de opciones de:

  • un (evaluado completamente) secuencia perezosa ex perezoso (doall ...)
  • una lista para el acceso secuencial (apply list (my-lazy-seq)) OR (into() ...)
  • un vector para el acceso aleatorio tarde (vec (my-lazy-seq))
  • un mapa o un conjunto si tiene algún propósito especial.

Puede tener cualquier tipo de secuencia que la mayoría de las suites necesite.

+0

Esta es la mejor respuesta. –

+3

La respuesta aceptada es técnicamente correcta, pero esta respuesta fue muy útil para mí. Intenté mapear una función sobre un vector y luego escupir los resultados a un archivo, e incluso después de llamar a doall, el archivo contenía "[email protected]" en lugar del contenido de la secuencia. Llamar a vec en el mapa de valor devuelto me dio lo que necesitaba escupir en el archivo. –

+1

@JesseRosalia Es bueno saber que la única respuesta de Rich Hickey en todo SO era técnicamente correcta. ;-) –

18

Este tipo rico parece saber su clojure y tiene toda la razón.
Buth creo que este código fragmento, usando tu ejemplo, podría ser un complemento útil a esta pregunta:

=> (realized? (take 3 (repeatedly rand))) 
false 
=> (realized? (doall (take 3 (repeatedly rand)))) 
true 

De hecho tipo no ha cambiado, pero realización ha

+2

Vale la pena señalar, sin embargo, que no es necesario forzar toda la secuencia para que 'realize?' para devolver 'true'. P.ej. '(dejar [r (rango) r? (realizado? r)] (doall (tomar 1 r)) [r? (realizado? r)]) => [falso verdadero]' –

+15

Este tipo Rico: D haha ​​ – nimrod

+7

@ nimrod :) sin embargo, el juego de palabras estaba destinado a estar en "hís clojure". – Peter

6

me encontré con este esta publicación blog acerca de doall no es recursiva. Para eso, encontré el primer comentario en la publicación que hizo el truco. Algo a lo largo de las líneas de:

(use 'closure.walk) 
(postwalk identity nested-lazy-thing) 

he encontrado este útil en una unidad de prueba donde quería forzar la evaluación de algunas aplicaciones anidadas de map para forzar una condición de error.

Cuestiones relacionadas