0

所以基本上我有一个计算step,它接受以前的结果并输出 a 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

在我的电脑上溢出

4

2 回答 2

3

您被懒惰所困扰:每次调用step某个 valuex时,GHC 都会创建一个 thunk step x,在需要最终值之前不会对其进行评估。

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

于 2013-05-14T10:54:29.890 回答
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
于 2013-05-14T20:15:17.913 回答