处理IO和MonadRandom以及链式计算时出现溢出问题

时间:2013-05-14 09:05:00

标签: haskell monads

所以基本上我有一个计算step,它接受​​一个先前的结果并输出一个Rand g Path,其中Path是一个自定义数据类型(把它想象成一个旅行的推销员类型问题)。我让MonadRandom处理所有生成器传递和东西。

我想找到这个计算的第n个组成部分。现在我正在使用

thecomputation :: (RandomGen g) => Rand g Path
thecomputation = (iterate (>>= step) (return startingPath)) !! n

然后打印出来我会跑

main = do
  res <- evalRandIO thecomputation
  print res

但是,我有一个问题

如果我选择足够高n(我需要大约10 ^ 6),我会得到堆栈溢出。

我设法跟踪问题,因为计算实际上是一个重组(嵌套?)IO对象。这是一系列IO计算,因此ghc必须跟踪嵌套IO的所有层,并且在足够的层之后,它会放弃。

我该怎么处理这件事?在一种命令式语言中,实际上并没有多少。但是我该怎么办呢?我应该强迫一些IO进行评估还是......?

在这个网站上有一个类似的问题,但我无法从接受的答案中得到任何帮助,所以我仍然很丢失

具体例子

import System.Random
import Control.Monad.Random
import Control.Monad

data Path = DoublePath Double deriving Show

step :: (RandomGen g) => Path -> Rand g Path
step (DoublePath x) = do
  dx <- getRandom
  return (DoublePath ((x + dx)/x))

thecomputation :: (RandomGen g) => Rand g Path
thecomputation = (iterate (>>= step) (return (DoublePath 10.0))) !! 1000000

main = do
  result <- evalRandIO thecomputation
  print result

在我的电脑上溢出

2 个答案:

答案 0 :(得分:3)

你被懒惰所困扰:每当你在某个值step上调用x时,GHC就会创建一个thunk step x,直到需要最终值才会对其进行评估。

一个简单的解决方法是在其参数中使step严格,例如通过DoublePath !x上的模式匹配(并使用-XBangPatterns)或在函数体之前插入x `seq`。然后你的代码完成没有堆栈溢出(呵呵)。

答案 1 :(得分:2)

足以使类型严格。这应该是第二种性质,特别是对于数字和其他“无法使用”的参数,并且不需要语言扩展。

data Path = DoublePath !Double deriving Show

 -- $ ghc -O2 doublepath.hs
 -- ...
 -- $ time ./doublepath
 -- DoublePath 1.526581416150007

 -- real    0m2.516s
 -- user    0m2.307s
 -- sys 0m0.092s