He estado jugando con el escritor Mónada recientemente, y me he encontrado con lo que parece ser una fuga de espacio. No puedo decir que aún entiendo completamente estas cosas , así que me gustaría saber qué está pasando aquí y cómo solucionarlo.Fugas de espacio, y escritores, y sumas (¡oh!)
En primer lugar, aquí es cómo puedo desencadenar este error:
import Control.Monad.Writer
import Data.Monoid
foo :: Integer -> Writer (Sum Integer) Integer
foo 0 = return 0
foo x = tell (Sum x) >> foo (pred x)
main = print $ runWriter $ foo 1000000
me sale:
Stack space overflow: current size 8388608 bytes.
Use `+RTS -Ksize -RTS' to increase it.
Para entender esto mejor, he vuelto a implementar una funcionalidad similar sin Writer o Suma, y si Mantengo las cosas bien y perezoso, obtengo el mismo error :
bar :: Integer -> (Integer, Integer)
bar x = bar' 0 x
where bar' c 0 = (0, c)
bar' c x = bar' (c + x) (pred x)
Pero puedo remediar esto mediante la adición seq
a la ecuación:
bar' c x = c `seq` bar' (c + x) (pred x)
He intentado seq
ing varios trozos de mi función foo
, pero eso no parece para ayudar. Además, traté de usar Control.Monad.Writer.Strict
, pero tampoco hace la diferencia.
¿Tiene que ser estricto de alguna manera? O me estoy perdiendo algo completamente diferente?
Notas
- que pueda tener mi terminología mal aquí. De acuerdo con Space leak zoo, mi problema se clasificaría como un "desbordamiento de pila", y si es , ¿cómo convertiría
foo
a un estilo más iterativo? ¿Es mi manual recursion el problema? - Después de leer Haskell Space Overflow, tuve la idea de compilar con
-O2
, solo para ver qué pasa. Esto puede ser un tema para otra pregunta, pero con optimizaciones, incluso miseq
'dbar
función no se ejecuta. Actualización: Este problema desaparece si agrego-fno-full-laziness
.
'Suma' es un 'tipo nuevo' por lo que es tan estricto o flojo como el tipo subyacente. – hammar