Cómo entender la szy-seq de clojure
Estoy tratando de entender clojurelazy-seq
operador, y el concepto de evaluación perezosa en general. Conozco la idea básica detrás del concepto: la evaluación de una expresión se retrasa hasta que se necesita el valor.
En general, esto se puede lograr de dos maneras:
en tiempo de compilación utilizando macros o formas especiales;en tiempo de ejecución utilizando funciones lambdaCon las técnicas de evaluación diferida, es posible construir estructuras de datos infinitas que se evalúan como consumidas. Estas secuencias infinitas utilizan lambdas, cierres y recursiones. En clojure, estas estructuras de datos infinitas se generan usandolazy-seq
ycons
formas
Quiero entender comolazy-seq
¿Es mágico? Sé que en realidad es una macro. Considere el siguiente ejemplo.
(defn rep [n]
(lazy-seq (cons n (rep n))))
Aquí elrep
La función devuelve una secuencia de tipo vagamente evaluadaLazySeq
, que ahora se puede transformar y consumir (así evaluado) utilizando la secuencia API. Esta API proporciona funcionestake
, map
, filter
yreduce
.
En la forma expandida, podemos ver cómo se utiliza lambda para almacenar la receta de la celda sin evaluarla de inmediato.
(defn rep [n]
(new clojure.lang.LazySeq (fn* [] (cons n (rep n)))))
Pero¿Cómo funciona realmente la secuencia API?LazySeq
?Lo que realmente sucede en la siguiente expresión?(reduce + (take 3 (map inc (rep 5))))
map
aplicado a la secuencia,cómotake
limitar la secuencia ycomo funciona la terminalreduce
evaluar la secuencia?También,¿Cómo funcionan estas funciones con unaVector
o unLazySeq
?
También,¿Es posible generar estructuras de datos infinitas anidadas??: lista que contiene listas, que contiene listas, que contiene listas ... va infinitamente ancho y profundo, evaluado como consumido con la secuencia API?
Y la última pregunta¿Hay alguna diferencia práctica entre esto
(defn rep [n]
(lazy-seq (cons n (rep n))))
y esto?
(defn rep [n]
(cons n (lazy-seq (rep n))))