私は最近 Writer モナドをいじっていて、スペースリークのように見えるものに出くわしました。これらのことをまだ完全に理解しているとは言えませんので、ここで何が起こっているのか、そしてそれを修正する方法を知りたいです.
まず、このエラーをトリガーする方法は次のとおりです。
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.
これをよりよく理解するために、Writer または Sum を使用せずに同様の機能を再実装しました。
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
なんか厳しくする必要ある?それとも、まったく違うものを見逃していますか?
ノート
- ここで用語が間違っている可能性があります。Space leak Zooによると、私の問題は「スタック オーバーフロー」に分類されます。その場合、
foo
より反復的なスタイルに変換するにはどうすればよいですか? 私の手動再帰が問題ですか? - Haskell Space Overflowを読んだ後
-O2
、何が起こるかを確認するために、 でコンパイルするという考えが浮かびました。これは別の質問のトピックかもしれませんが、最適化すると、私seq
のbar
関数でさえ実行に失敗します。 更新: を追加すると、この問題はなくなり-fno-full-laziness
ます。