鉴于此代码段:
someFunction x = print x `seq` 1
main = do print (someFunction "test")
为什么执行代码时不print x
打印test
?
$./seq_test
1
如果我用它替换它,error
我可以检查左操作数seq
是否确实被评估。
我怎样才能达到我的预期输出:
test
1
只修改someFunction
?
评估一个IO
动作什么都不做。这是正确的!
如果您愿意,IO
类型的值仅仅是“指令列表”。因此,您所做的seq
只是强制程序确定如果实际使用了该操作应该做什么之一。并且使用一个动作与评估无关,这意味着将它单子绑定到调用。但是,正如您所说,因为它是一个具有非单子签名的函数,所以这里不可能发生。main
someFunction
你能做的......但不要,是
import Foreign
someFunction x = unsafePerformIO (print x) `seq` 1
这实际上将评估与IO
执行结合起来。这在 Haskell 中通常是一个非常糟糕的主意,因为评估可能以完全不可预见的顺序发生,可能与您想象的次数不同(因为编译器假定引用透明)以及其他混乱场景。
正确的解决方案是将签名更改为单子:
someFunction :: Int -> IO Int
someFunction x = do
print x
return 1
main = do
y <- someFunction "test"
print y
1碰巧的是,即使没有seq
. 更多细节只能通过执行动作获得。
seq
将表达式评估为弱头范式,它只是最外层的构造函数(或 lambda 应用程序)。表达式print x
已经在 WHNF 中,所以seq
什么都不做。
您可以使用该功能获得您正在寻找的结果Debug.Trace.trace
。