鉴于此代码段:
someFunction x = print x `seq` 1
main = do print (someFunction "test")
为什么代码执行时print x
不打印test
?
$./seq_test
1
如果我将其替换为error
,我可以检查确实评估了seq
的左操作数。
我怎样才能实现预期的输出:
test
1
仅修改someFunction
?
答案 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
获取您正在寻找的结果。