Haskell - 在Rand monad中计算出计算结果

use*_*438 6 random monads haskell timeout lazy-evaluation

我想用Haskell评估随机计算,并使用Control.Monad.Random库超时.以下工作正常:

ghci> import System.Timeout
ghci> import Control.Monad.Random
ghci> timeout 1000 . evalRandIO $ getRandomR (True, False)
Just True
Run Code Online (Sandbox Code Playgroud)

但是,如果我们有一个Rand StdGen a永不终止的类型计算(即评估到底部),这种方法似乎不起作用.例如:

ghci> let f = f :: Rand StdGen Bool
ghci> timeout 1000 $ evalRandIO f
Just
Run Code Online (Sandbox Code Playgroud)

在这里GHCI打印"Just",然后无限期地挂起试图评估f.能否了解Haskell运行时的人比我更能解释为什么会这样,以及如何解决它?我的猜测是表达式evalRandIO f被评估为WHNF,因此timeout 10认为计算将终止,但我真的不知道.

bhe*_*ilr 5

如果你做某些事情,这可能会更有意义

> Just x <- timeout 1000 $ evalRandIO f
> :t x
x :: Bool
> x
Interrupted.
Run Code Online (Sandbox Code Playgroud)

计算本身正在完成,即它到达WHNF,所以timeout没有抓住它.该timeout 1000函数本身完成并返回Just undefined.一个例子,你可以得到timeout赶底的评价会

> import Control.DeepSeq
> :set +m    -- Multiline mode
> let f :: Bool
|     f = f
|
> timeout 1000000 $ deepseq f (return f)
Nothing
Run Code Online (Sandbox Code Playgroud)

您将看到它挂起一秒钟,然后Nothingdeepseq未完成评估时返回,f以便它可以执行return f.

所以,是的,你的问题源于f = f被评估为WHNF而不是NF 的事实.为了强制NF,你需要使用类似的东西deepseq.另一个可能更简单的例子就是使用$!运算符,例如:

> let f :: Rand StdGen Bool
|     f = f
|
> timeout 1000000 $ evalRandIO $! f
Nothing
Run Code Online (Sandbox Code Playgroud)