Недавно я играл с Writer Monad, и я столкнулся с что кажется утечкой в пространстве. Я не могу сказать, что я полностью понимаю эти все еще, поэтому я хотел бы знать, что происходит здесь, и как это исправить.
Во-первых, вот как я могу вызвать эту ошибку:
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
Я получаю:
Stack space overflow: current size 8388608 bytes.
Use `+RTS -Ksize -RTS' to increase it.
Чтобы понять это лучше, я реализовал аналогичную функциональность без писателя или суммы, и если я буду держать все хорошо и лениво, я получаю такая же ошибка:
bar :: Integer -> (Integer, Integer)
bar x = bar' 0 x
where bar' c 0 = (0, c)
bar' c x = bar' (c + x) (pred x)
Но я могу исправить это, добавив seq
к уравнению:
bar' c x = c `seq` bar' (c + x) (pred x)
Я пробовал seq
различные биты моей функции foo
, но это не кажется
помогать. Кроме того, я попытался использовать Control.Monad.Writer.Strict
, но
также не имеет значения.
Нужно ли Sum
быть строгим? Или я чего-то не хватает
совершенно разные?
Примечания
- Возможно, у меня есть моя терминология. Согласно Космическая утечка
зоопарк, моя проблема будет классифицирована как "переполнение стека", и если
что случай, как бы преобразовать
foo
в более итеративный стиль? Является ли мое руководство рекурсия проблема? - После прочтения Haskell Space Overflow у меня было
идея скомпилировать с
-O2
, просто чтобы узнать, что происходит. Это может быть тема для другой вопрос, но с оптимизацией даже моя функцияseq
'dbar
не запускается. Обновление. Эта проблема исчезает, если я добавляю-fno-full-laziness
.