为什么我不能用seq强制执行IO操作?

时间:2013-12-02 09:07:24

标签: haskell io seq

鉴于此代码段:

someFunction x = print x `seq` 1

main = do print (someFunction "test")

为什么代码执行时print x不打印test

$./seq_test 
1

如果我将其替换为error,我可以检查确实评估了seq 的左操作数

我怎样才能实现预期的输出:

test
1

仅修改someFunction

2 个答案:

答案 0 :(得分:11)

评估IO操作无所作为。那是对的!

如果您愿意,IO类型的值仅仅是“指令列表”。所以你用seq做的就是强迫程序确保 1 应该应该如果 >。使用动作与评估无关,它意味着将其单独绑定到main调用。但是,正如你所说,someFunction是一个带有非monadic签名的函数,这在这里不可能发生。

你能做什么...... 但不,是

import Foreign

someFunction x = unsafePerformIO (print x) `seq` 1

这实际上将评估与IO执行结合起来。这通常是Haskell中一个非常糟糕的主意,因为评估可能发生在完全不可预测的顺序,可能发生的次数可能比您想象的要多(因为编译器假设参考透明度),以及其他混乱场景。

正确的解决方案是将签名更改为monadic:

someFunction :: Int -> IO Int
someFunction x = do
     print x
     return 1

main = do
     y <- someFunction "test"
     print y

1 尽管如此,即使没有seq,程序仍然尽可能确定。只有通过执行操作才能获得更多细节。

答案 1 :(得分:1)

seq将表达式计算为弱头正常形式,这只是最外层的构造函数(或lambda应用程序)。表达式print x已经在WHNF中,因此seq没有做任何事情。

您可以使用函数Debug.Trace.trace获取您正在寻找的结果。