所以基本上我有一个计算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
在我的电脑上溢出
答案 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