【问题标题】:MonadRandom: why stack overflow happens?MonadRandom:为什么会发生堆栈溢出?
【发布时间】:2012-12-15 18:28:29
【问题描述】:

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

【问题讨论】:

    标签: haskell random stack-overflow monads


    【解决方案1】:

    出现问题是因为您将 IO 构建到您的 manyTdata 函数中。 monad 转换器最终是RandT g IO Tdata 类型。因为每个元素 你的无限列表可以包含IO 动作,无限列表的整体 manyTdata 返回的函数必须在函数返回之前完全进行评估 任何结果。

    最简单的解决方案是使用Rand 而不是RandT,就像使用变压器一样 无论如何,这里并不是很有用;您还可以将基本单子更改为类似 Identity monad 通过将 manyTdata 更改为

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

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

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

    【讨论】:

      猜你喜欢
      • 2014-09-19
      • 1970-01-01
      • 1970-01-01
      • 2018-07-01
      • 2021-06-18
      • 2012-05-10
      • 2017-05-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多