我想使用Control.Monad.Random
库在超时时评估Haskell中的随机计算。以下工作正常:
ghci> import System.Timeout
ghci> import Control.Monad.Random
ghci> timeout 1000 . evalRandIO $ getRandomR (True, False)
Just True
然而,如果我们有一个永远不会终止的类型Rand StdGen a
的计算(即评估到底部),这种方法似乎不起作用。例如:
ghci> let f = f :: Rand StdGen Bool
ghci> timeout 1000 $ evalRandIO f
Just
这里GHCI打印" Just"然后无限期地挂起,试图评估f
。能否了解Haskell运行时的人比我更能解释为什么会这样,以及如何解决它?我的猜测是表达式evalRandIO f
被评估为WHNF,因此timeout 10
认为计算将终止,但我真的不知道。
答案 0 :(得分:5)
如果您要执行类似
的操作,这可能会更有意义> Just x <- timeout 1000 $ evalRandIO f
> :t x
x :: Bool
> x
Interrupted.
计算本身正在完成,即它到达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
您会看到它挂起一秒钟,然后在Nothing
未完成评估deepseq
时返回f
,以便它可以执行return f
。
所以是的,你的问题源于f = f
被评估为WHNF而不是NF的事实。为了强制使用NF,您需要使用类似deepseq
的内容。另一个可能更简单的例子就是使用$!
运算符,例如:
> let f :: Rand StdGen Bool
| f = f
|
> timeout 1000000 $ evalRandIO $! f
Nothing