clojure functional-programming lazy-evaluation

Uso de secuencia diferida de Clojure



functional-programming lazy-evaluation (1)

Una llamada lazy-seq simplemente ejecuta el cuerpo una vez que se accede a ella, luego se almacena en caché y devuelve el mismo resultado cada vez que se vuelve a llamar en el futuro.

Si desea usar esto para construir secuencias largas (o incluso infinitas), entonces debe anidar recursivamente otras llamadas de lazy-seq en la secuencia devuelta. Aquí está el caso más simple que puedo pensar:

(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)

Cualquier llamada (ints-from) produce una secuencia que comienza con n, seguida de una secuencia perezosa de (ints-from (inc n)). Es una lista infinita, pero eso no es un problema porque lazy-seq asegura que (int-from (inc n)) solo se invoque cuando sea necesario. Podrías probar exactamente el mismo código sin lazy-seq y obtendrías un StackOverflowError muy rápidamente.

lazy-seq es solo una de las muchas formas posibles de crear secuencias diferidas, y a menudo no es la más conveniente. Las siguientes son algunas otras maneras interesantes / útiles para crear secuencias perezosas:

; 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)

Tengo problemas para entender cómo se crea una secuencia perezosa en Clojure.

La documentación para la macro no está nada clara para mí:

Uso: (lazy-seq & body) Toma un cuerpo de expresiones que devuelve un ISeq o nil, y produce un objeto Seqable que invocará el cuerpo solo la primera vez que se llama a seq, y guardará en caché el resultado y lo devolverá en todos los siguientes llamadas seq.

Todos los ejemplos que he visto, parecen hacer algo como lo siguiente:

; 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))) )

Entonces, lo primero que no entiendo es que, dado que lazy-seq está fuera del llamado a conj, ¿cómo impide que conj genere una secuencia infinita en la evaluación?

Mi segunda pregunta es, ¿las definiciones de secuencia diferida siempre toman esta forma general?