He escrito dos versiones del problema de nqueens y creo que deberían tener una eficacia similar, pero no es así. Creo que se debe al comportamiento de evaluación perezosa de Haskell. Por favor alguien puede explicar cómo funciona para el siguiente ejemplo,Necesito ayuda para comprender el comportamiento de evaluación de pereza de Haskell
nqueens1 n 1 = [[i] | i <- [1..n]]
nqueens1 n k = [ i:q | i <- [1..n], q <- (nqueens1 n (k - 1)), isSafe i q k]
isSafe i q n = isSafeHelper i (zip q [(n-1),(n-2)..1])
where isSafeHelper i [] = True
isSafeHelper i (x:xs) = (i /= fst x) && abs(i - (fst x)) /= abs(n - (snd x)) &&
isSafeHelper i xs
nqueens2 n 1 = [[i] | i <- [1..n]]
nqueens2 n k = [ i:q | i <- [1..n], q <- boards, isSafe i q k]
where boards = nqueens2 n (k-1)
poder evaluarlas llamando nqueens1 8 8 8 8 o nqueens2 de evaluarlo para un tablero de tamaño 8.
Mientras nqueens2 funciona bastante eficientemente nqueens1 tiene problemas de rendimiento. Creo que es porque la llamada recursiva (nqueens n (k-1)) se está evaluando varias veces. Desde mi comprensión de la evaluación perezosa de Haskells, este no debería ser el caso.
Ayúdeme a comprender este comportamiento.
Gracias de antemano.
"La evaluación perezosa" se trata de evaluar las cosas tarde - no se trata de evitar que evalúan algo que muchas veces. –
@DanielWagner En realidad, la diferencia entre la evaluación diferida y la llamada por nombre es exactamente que ciertas expresiones que se evaluarían varias veces con la función llamar por nombre solo se evalúan una vez mediante la evaluación diferida. Sin embargo, eso no está relacionado con el problema aquí. – sepp2k
@ sepp2k Tienes razón, debería haber sido más preciso, ya sea diciendo "llamar por nombre" en lugar de "evaluación perezosa" o diciendo "memorando" en lugar de "evitar evaluar muchas veces". –