Buenas, comienzo por aclarar que no hay ninguna pregunta en este post. Sólo vengo a comentar que entendí qué fue lo que pasó en la clase de práctico del viernes y en el momento no logramos explicar.
Para mostrar las ventajas de la evaluación perezosa se planteó como ejemplo el caso de la función factorial
fac 0 = 1
fac n = n * fac (n-1)
A continuación se evaluó dicha función en un valor suficientemente grande como para que el tiempo de calcularlo fuera apreciable. Lo que observamos fue que el resultado de este cómputo fue 0, y dijimos "qué casualidad que justo cayó ahí al reducirlo mod n". La realidad es que esto no es casualidad si no que es una particularidad de la función factorial.
Según la documentación de Haskell, "todas las operaciones aritméticas son realizadas módulo 2^n donde n es el número de bits en el tipo", y este n no necesariamente es 32 ni 64 ya que por cuestiones de implementación se pueden usar algunos bits para almacenar otro tipo de información.
Esto implica que una vez que para un n_0, fac n_0 sea múltiplo de 2^n, para todo n mayor o igual a ese n_0, fac n_0 también lo será (recordemos que a = b mod n => ac = bc mod n, en particular para a = fac n_0 , b = 0, c = n_0 +1, etc). Para concluir, no hace falta que n_0 sea 2^n si no que la suma de las multiplicidades del 2 como factor de los enteros menores o iguales a n_0 sea mayor o igual a n. Ejemplo: Si n fuera 3, no haría falta calcular fac 8 si no que fac 6 bastaría puesto que fac 6 = 6*5*4*3*2 = (2*3)*5*(2*2)*3*2 y en este caso la multiplicidad del 2 como factor es 4 >= 3.
Todo esto también explica por qué cuando quitábamos dígitos del parámetro al principio seguía dando 0 y al quitar suficientes daba algo negativo. Al principio la multiplicidad del 2 seguía siendo suficientemente grande. En el momento que pasó a ser menor a n, empezamos a ver el resultado de la operación (que no era múltiplo de 2^n) reducido mod 2^n.