Timeout and unsafePerformIO



我在Haskell中得到了一些实践,探索了一些我不熟悉的领域,但我无法理解我在混合System.TimeoutSystem.IO.Unsafe时得到的行为。

我懒洋洋地读一个流,用getContents,过滤它与一个纯函数,并输出结果。一个典型的过滤器是这样的:

import Data.List(break)
import System.Timeout(timeout)
import System.IO.Unsafe(unsafePerformIO)
main = do
    text <- getContents 
    putStr $ aFilter text
aFilter text = h ++ t where
    (h, t) = getUntil "n" text
getUntil separator text = break (x -> (separator!!0) == x) text

使用这样的过滤器,程序按照预期读取所有标准输入,并输出到标准输出。但是如果我这样写:

aFilter text = result where
    l = consumeWithTimeout (getUntil "n" text)
    result = case l of
        Nothing -> "Timeout!n"
        Just (h, t) -> h ++ t
consumeWithTimeout (x, y) = unsafePerformIO $! timeout 6 $! deepseq x (return (x, y))

我希望我的程序立即超时,打印"超时!"消息,然后关闭。相反,它挂起在那里,等待输入。

我认为timeout函数在程序启动时评估是错误的吗?我希望它是,因为我立即将其返回值的一部分写入标准输出,并且每次我输入一行时软件都会做出反应。是unsafePerformIO插入某种懒惰到我的功能?还是将懒惰插入System.Timeout的内部?

原因是return $! (x, y)没有严格求值xy。它只求元组构造函数的值,而元组构造函数不一定求其域xy的值。

所以在你的程序中发生的是,return $! (x, y)立即成功,而没有实际尝试计算xy。然后h ++ t部分开始计算h,这是它最终开始阻塞输入的时候。

顺便说一下,这就是你不应该使用unsafePerformIO的原因:你不能很容易地推断出效果何时实际发生。

我希望

timeout 6 $! return $! (x, y)
在正常工作负载下,

永远不会触发超时。上面的代码不强制xy求值。也许使用evaluate会有帮助。

此外,在此任务中使用unsafePerformIO看起来有些多余。使用unsafePerformIO只能作为最后的手段。

相关内容

  • 没有找到相关文章

最新更新