繁体   English   中英

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

[英]MonadRandom: why stack overflow happens?

这个问题肯定是针对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是不是很懒?还是其他呢? 以及在这种情况下如何定义堆栈溢出的原因?

出现问题是因为您正在将IO manyTdatamanyTdata函数中。 monad变压器最终成为RandT g IO Tdata类型。 因为你的无限列表中的每个元素可以由IO操作,返回的无限列表的整体manyTdata必须完全评估之前,该函数可以返回任何结果。

最简单的解决方案是使用Rand而不是RandT ,因为使用RandT在这里并不是真正有用的。 你也可以改变基单子到类似的Identity通过改变单子manyTdata

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

这将在有限的时间内终止。 与堆栈大小有关的错误仅是递归扩展IO操作列表的结果。 您的代码说要对所有这些动作进行排序,因此必须全部执行,这与懒惰无关。

除了使用randomTdata ,还需要考虑其他randomTdata ,请考虑使Tdata成为Random类的实例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM