web-dev-qa-db-fra.com

Comment convertir une séquence paresseuse en non paresseux dans Clojure

J'ai essayé ce qui suit dans Clojure, en m'attendant à ce que la classe d'une séquence non paresseuse soit renvoyée:

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

Cependant, cela renvoie toujours clojure.lang.LazySeq. Je suppose que doall évalue la séquence entière, mais renvoie la séquence d'origine car elle est toujours utile pour la mémorisation.

Alors, quel est le moyen idiomatique de créer une séquence non paresseuse à partir d'une séquence paresseuse?

90
Tim Clemons

doall est tout ce dont vous avez besoin. Ce n'est pas parce que le seq a le type LazySeq qu'il a en attente d'évaluation. Les séquences paresseuses mettent en cache leurs résultats, donc tout ce que vous devez faire est de parcourir la séquence paresseuse une fois (comme le fait doall) afin de tout forcer, et donc de la rendre non paresseuse. seq ne pas force la collection entière à être évaluée.

150
Rich Hickey

Il s'agit dans une certaine mesure d'une question de taxonomie. une séquence paresseuse n'est qu'un type de séquence tout comme une liste, un vecteur ou une carte. Donc, la réponse est bien sûr "cela dépend du type de séquence non paresseuse que vous souhaitez obtenir:
Faites votre choix parmi:

  • une séquence paresseuse ex-paresseuse (entièrement évaluée) (doall ... )
  • une liste d'accès séquentiel (apply list (my-lazy-seq)) OR (into () ...)
  • un vecteur pour un accès aléatoire ultérieur (vec (my-lazy-seq))
  • une carte ou un ensemble si vous avez un but particulier.

Vous pouvez avoir le type de séquence le plus adapté à vos besoins.

66
Arthur Ulfeldt

Ce gars riche semble connaître son clojure et a absolument raison.
Mais je pense que cet extrait de code, en utilisant votre exemple, pourrait être un complément utile à cette question:

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

En effet type n'a pas changé mais réalisation a

21
Peter

Je suis tombé sur ce sujet blog post à propos de doall non récursif. Pour cela, j'ai trouvé que le premier commentaire dans le post a fait l'affaire. Quelque chose dans le sens de:

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

J'ai trouvé cela utile dans un test unitaire où je voulais forcer l'évaluation de certaines applications imbriquées de map pour forcer une condition d'erreur.

7
leeor
(.getClass (into '() (take 3 (repeatedly Rand))))
5
stupito