Lo primero a tener en cuenta es que, por sí solo, ese código no hace nada. Es solo un montón de expresiones matemáticas y no importa qué tan circular sea hasta que intentemos extraer algunos valores de ellas. ¿Como hacemos eso?
que podíamos hacer:
print $ take 1 primes1
No hay problema aquí. Podemos tomar el primer valor de primes1 sin mirar a cualquier parte del código recursivo, que está ahí explícitamente como 2. ¿Qué pasa:
print $ take 3 primes1
Vamos a intentar expandir primes1
para obtener algunos valores cabo. Para mantener estas expresiones manejables, ahora ignoro las partes print
y take
, pero recuerda que solo estamos haciendo este trabajo debido a ellas. primes1
es:
primes1 = 2 : filter prime [3..]
Tenemos nuestro primer valor, y el primer paso en nuestro segundo es la ampliación de filtro. Si este fuera un lenguaje estricto, intentaríamos ampliar [3 ..] primero y obtener atascado. Una posible definición de filtro es:
filter f (x:xs) = if f x then x : filter f xs else filter f xs
lo que da:
primes1 = 2 : if prime 3 then 3 : filter prime [4..] else filter prime [4..]
Nuestro siguiente paso tiene que ser averiguar si prime 3
es verdadera o falsa, así que vamos a expandirlo usando nuestras definiciones de prime
, ldp
y ldpf
.
primes1 = 2 : if ldp 3 == 3 then 3 : filter prime [4..] else filter prime [4..]
primes1 = 2 : if ldpf primes1 3 == 3 then 3 : filter prime [4..] else filter prime [4..]
Ahora, las cosas se ponen interesantes, primes1 referencia a sí mismo y necesita ldpf el primer valor hacer su cálculo. Afortunadamente, podemos obtener el primer valor fácilmente.
primes1 = 2 : if ldpf (2 : tail primes) 3 == 3 then 3 : filter prime [4..] else filter prime [4..]
Ahora, que se aplican las cláusulas de guardia en ldpf y encontrar 2^2 > 3
, por lo tanto, ldpf (2 : tail primes) 3 = 3
.
primes1 = 2 : if 3 == 3 then 3 : filter prime [4..] else filter prime [4..]
primes1 = 2 : 3 : filter prime [4..]
Ahora tenemos nuestro segundo valor. Tenga en cuenta que el lado derecho de nuestra evaluación nunca creció especialmente grande y que nunca tuvimos que seguir el ciclo recursivo muy lejos.
primes1 = 2 : 3 : if prime 4 then 4 : filter prime [5..] else filter prime [5..]
primes1 = 2 : 3 : if ldp 4 == 4 then 4 : filter prime [5..] else filter prime [5..]
primes1 = 2 : 3 : if ldpf primes1 4 == 4 then 4 : filter prime [5..] else filter prime [5..]
primes1 = 2 : 3 : if ldpf (2 : tail primes1) 4 == 4 then 4 : filter prime [5..] else filter prime [5..]
Utilizamos la cláusula de guardia rem 4 2 == 0
, por lo tanto, obtenemos 2 aquí.
primes1 = 2 : 3 : if 2 == 4 then 4 : filter prime [5..] else filter prime [5..]
primes1 = 2 : 3 : filter prime [5..]
primes1 = 2 : 3 : if prime 5 then 5 : filter prime [6..] else filter prime [6..]
primes1 = 2 : 3 : if ldp 5 == 5 then 5 : filter prime [6..] else filter prime [6..]
primes1 = 2 : 3 : if ldpf primes1 5 == 5 then 5 : filter prime [6..] else filter prime [6..]
primes1 = 2 : 3 : if ldpf (2 : tail primes) 5 == 5 then 5 : filter prime [6..] else filter prime [6..]
No hay coincidencias de guardia, por lo que son recursivos:
primes1 = 2 : 3 : if ldpf (tail primes) 5 == 5 then 5 : filter prime [6..] else filter prime [6..]
primes1 = 2 : 3 : if ldpf (3 : tail (tail primes)) 5 == 5 then 5 : filter prime [6..] else filter prime [6..]
Ahora 3^2 > 5
manera que la expresión es 5.
primes1 = 2 : 3 : if 5 == 5 then 5 : filter prime [6..] else filter prime [6..]
primes1 = 2 : 3 : 5 : filter prime [6..]
única Necesitamos tres valores, por lo que la evaluación puede parar.
Por lo tanto, ahora para responder a sus preguntas. Una lista diferida es aquella que solo requiere que evaluemos lo que necesitamos, y la 2 ayuda porque garantiza que cuando lleguemos al paso recursivo siempre tengamos suficientes valores ya calculados. (Imagine expandir esa expresión si no conociéramos el 2, terminaríamos atrapados en un bucle muy bonito rápidamente.)
un círculo vicioso es aquel en el que se transmiten desagrados, p. boy1 bullies boy2, boy2 le dice a su padre que se enoja y es malo con sus empleados, uno de los cuales es padre de niño1 que luego lleva su frustración a su hijo, quien luego intimida a boy2 ... Un círculo no vicioso es un ciclo eso no tiene nada de desagradable. –
Correcto, estoy familiarizado con el término en otros contextos, pero nunca lo he visto aplicado al análisis de programas. ¿Es esto un haskellismo con el que no estoy familiarizado? – Gian
No es un Haskell-ismo. 'círculo vicioso' es un idioma en idioma inglés (si es exclusivo de inglés, no lo sé). Cualquier secuencia circular de eventos (ya sea en la vida o en la programación) que desearía _no_ ser circular podría denominarse un 'círculo vicioso'. –