0

This question is certainly for stackoverflow.com

here is the sample

module Main where

import Control.Monad.Random
import Control.Exception

data Tdata = Tdata Int Int Integer String

randomTdata :: (Monad m, RandomGen g) => RandT g m Tdata
randomTdata = do
  a <- getRandom
  b <- getRandom
  c <- getRandom
  return $ Tdata a b c "random"


manyTdata :: IO [Tdata]
manyTdata = do
  g <- newStdGen
  evalRandT (sequence $ repeat randomTdata) g

main = do
  a <- manyTdata
  b <- evaluate $ take 1 a
  return ()

after compilation this return

Stack space overflow: current size 8388608 bytes.
Use `+RTS -Ksize -RTS' to increase it

How can it happen ? Is MonadRandom not lazy or what else ? And how to define the cause of stack overflow in cases like that ?

4

1 に答える 1

4

この問題は、関数IOを組み込んでいるために発生しますmanyTdata。モナド変換子は最終的にタイプになりRandT g IO Tdataます。無限リストの各要素はIOアクションで構成できるため、関数が結果を返す前に、によって返される無限リスト全体を完全manyTdataに評価する必要があります。

とにかく、ここではトランスフォーマーを使用することはあまり役に立たないため、最も簡単な解決策は、Randの代わりに使用することです。RandT次のように変更することで、ベースモナドをモナドのようなものに変更することもできIdentityますmanyTdata

manyTdata :: IO [Tdata]
manyTdata = do
  g <- newStdGen
  return $ runIdentity $ evalRandT (sequence $ repeat randomTdata) g

これは有限の時間で終了します。スタックサイズに関するエラーは、IOアクションのリストを再帰的に拡張した結果です。あなたのコードはこれらすべてのアクションをシーケンスするように言っているので、それらはすべて実行する必要があり、怠惰とは何の関係もありません。

を使用するのではなく、他に考えるべきことがある場合は、クラスのインスタンスをrandomTdata作成することを検討してください。TdataRandom

于 2012-12-15T18:46:18.397 に答える