0

这个问题肯定是针对stackoverflow.com的

这是示例

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 ()

编译后返回

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

怎么会发生?MonadRandom 不是懒惰还是什么?在这种情况下如何定义堆栈溢出的原因?

4

1 回答 1

4

The issue arises because you are building IO into your manyTdata function. The monad transformer ends up being of type RandT g IO Tdata. Because each element of your infinite list can consist of IO actions, the entirety of the infinite list returned by manyTdata must be evaluated completely before the function can return any results.

The simplest solution would be to use Rand instead of RandT, as using the tranformer isn't really useful here, anyway; you could also change the base monad to something like the Identity monad by changing manyTdata to

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

Which will terminate in a finite amount of time. The error concerning your stack size is simply a result of recursively expanding your list of IO actions. Your code says to sequence all of these actions, so they all have to be performed, it has nothing to do with laziness.

Something else to think about, rather than using randomTdata, consider making Tdata an instance of the Random class.

于 2012-12-15T18:46:18.397 回答