【发布时间】:2014-09-16 18:19:18
【问题描述】:
我previously 询问了一个关于如何强制严格评估以创建超时的问题。大多数时候使用seq/$!就足够了,deepseq适用于NFData的任何成员,但是如果我们使用一个奇怪的递归类型怎么办?假设我们有以下内容:
import Control.DeepSeq
import Control.Monad.Random
import Data.Maybe
import System.Timeout
newtype A = A { runA :: A -> Int -> Rand StdGen Bool }
-- a call to runA with this as the first input will always terminate
example1 :: A
example1 = A (\_ i -> (if i > 0 then getRandomR (True, False) else return False))
-- a call to runA with this as the first input will never terminate
example2 :: A
example2 = A (\_ _ -> runA example2 example2 0)
-- here it depends on the other input
-- will terminate with example1, not with example2 or 3
example3 :: A
example3 = A (\a _ -> runA a a 0)
我们能否编写一个超时函数来确定当我们调用runA x x 0 时,某个x 类型的A 值是否会在给定时间内终止?我们可以尝试像这样使用seq:
testTimeout :: A -> IO (Maybe Bool)
testTimeout x = timeout 1000 . evalRandIO $! runA x x 0
但是,这不适用于 example2 和 example3,因为对 runA 的调用被评估为 WHNF,但随后挂起,因为计算永远不会完成。用deepseq(即$!!)尝试同样的事情甚至不会编译,因为我们需要Rand StdGen Bool 的NFData 实例。那么,我们如何实现这个实例以使严格的评估/超时按预期工作?还是有其他方法可以做到这一点?
【问题讨论】:
标签: haskell timeout lazy-evaluation