MonadRandom:为什么堆栈溢出发生?

时间:2012-12-15 18:28:30

标签: haskell random stack-overflow monads

这个问题肯定适用于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不是懒惰还是其他什么?如何在这种情况下定义堆栈溢出的原因?

1 个答案:

答案 0 :(得分:4)

出现此问题是因为您正在IO功能中构建manyTdata。 monad变换器最终为RandT g IO Tdata类型。因为每个元素 您的无限列表可以包含IO个动作,无限列表的全部内容 在函数返回之前,manyTdata返回的完全必须被评估 任何结果。

最简单的解决方案是使用Rand代替RandT,就像使用转换器一样 反正在这里并不是真的有用;你也可以将基础monad更改为类似的东西 通过将Identity更改为

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

哪个会在有限的时间内终止。有关堆栈大小的错误 只是递归扩展您的IO操作列表的结果。你的代码说要对所有这些动作进行排序,所以它们都必须被执行,它与懒惰无关。

要考虑的其他事情,而不是使用randomTdata 使Tdata成为Random类的实例。