10

鉴于此代码段:

someFunction x = print x `seq` 1

main = do print (someFunction "test")

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

$./seq_test 
1

如果我用它替换它,error我可以检查左操作数seq 是否确实被评估。

我怎样才能达到我的预期输出:

test
1

只修改someFunction

4

2 回答 2

12

评估一个IO动作什么都不做。这是正确的!

如果您愿意,IO类型的值仅仅是“指令列表”。因此,您所做的seq只是强制程序确定如果实际使用了该操作该做什么之一。并且使用一个动作与评估无关,这意味着将它单子绑定到调用。但是,正如您所说,因为它是一个具有非单子签名的函数,所以这里不可能发生。mainsomeFunction

你能做的......但不要,是

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. 更多细节只能通过执行动作获得。

于 2013-12-02T09:30:09.377 回答
1

seq将表达式评估为弱头范式,它只是最外层的构造函数(或 lambda 应用程序)。表达式print x已经在 WHNF 中,所以seq什么都不做。

您可以使用该功能获得您正在寻找的结果Debug.Trace.trace

于 2013-12-02T09:31:20.960 回答