Clojure paresseux séquence d'utilisation

j'ai du mal à comprendre comment on crée une séquence paresseuse à Clojure.

la documentation pour la macro n'est pas du tout claire pour moi:

Usage: (lazy-seq & body) Prend un corps d'expressions qui renvoie un ISeq ou un nil, et donne un objet sensible qui n'invoquera le corps que la première fois seq est appelé, et mettra en cache le résultat et le retournera sur tous les seq appels.

tous les exemples que j'ai vus, semblent faire quelque chose comme ce qui suit:

; return everything in the sequence starting at idx n
(defn myseq-after-n [n]
  (...)
)

(def my-lazy-seq
  (lazy-seq (conj [init-value] (myseq-after-n 2)))
)

donc, la première chose que je ne comprends pas c'est, puisque lazy-seq est en dehors de l'appel à conj, comment empêche-t-il conj de générer une séquence infinie à l'évaluation?

ma deuxième question Est la suivante: les définitions des séquences paresseuses prennent-elles toujours cette forme générale?

42
demandé sur lightlazer 2011-02-14 15:46:20

1 réponses

un appel paresseux-seq exécute simplement le corps une fois qu'il est accédé pour la première fois, puis le cache et renvoie le même résultat chaque fois qu'il est appelé à nouveau dans le futur.

si vous voulez utiliser ceci pour construire des séquences longues (ou même infinies), alors vous devez recursively emboîter d'autres appels paresseux-seq dans la séquence retournée. Voici le cas le plus simple que je puisse imaginer:

(defn ints-from [n]
  (cons n (lazy-seq (ints-from (inc n)))))

(take 10 (ints-from 7))
=> (7 8 9 10 11 12 13 14 15 16)

tout appel (ints-à partir de n) produit une séquence commençant par n, suivi d'une séquence paresseuse de (ints-from (inc n)). C'est une liste infinie, mais ce n'est pas un problème car le paresseux-seq assure que (int-de inc (n)) seulement qui est appelé lorsque c'est nécessaire. Vous pourriez essayer exactement le même code sans les lazy-seq et vous obtiendriez un Stackoverfowerror très rapidement.

lazy-seq est juste une des nombreuses façons possibles de créer des séquences paresseuses, et il n'est souvent pas le plus pratique. Ce qui suit sont quelques autres façons intéressantes/utiles de créer paresseux séquences:

; range is an easy way to get an infinite lazy sequence of integers, starting with zero     
(take 10 (range))
=> (0 1 2 3 4 5 6 7 8 9)

; map produces lazy sequences, so the following is lazy 
(take 10 (map #(* % %) (range)))
=> (0 1 4 9 16 25 36 49 64 81)

; iterate is a good way of making infinite sequenes of the form x, f(x), f(f(x))..... 
(take 10 (iterate (partial * 2) 1))
=> (1 2 4 8 16 32 64 128 256 512)
56
répondu mikera 2011-02-14 17:23:58