私は最近 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ます。