import System.IO.Unsafe
main :: IO ()
main = do
_ <- return $ unsafePerformIO $ do
print "test2"
print "test"
Run Code Online (Sandbox Code Playgroud)
上面只输出test(当运行时runghc),我假设由于Haskell的惰性,第一个IO动作实际上没有得到评估.如何强制它评估和执行操作?
以上仅用于调试目的.
为了执行IO副作用,unsafePerformIO需要强制创建"纯"值(即,至少评估为WHNF).
不幸的是,你的main功能:
main = do
_ <- return $ unsafePerformIO $ do
print "test2"
print "test"
Run Code Online (Sandbox Code Playgroud)
desugars(根据Haskell98报告)成:
main = let ok _ = do { print "test" }
ok _ = fail "..."
in return (unsafePerformIO (print "test2")) >>= ok
Run Code Online (Sandbox Code Playgroud)
这相当于monad法律:
main = let ok _ = do { print "test" }
ok _ = fail "..."
in ok (unsafePerformIO (print "test2"))
Run Code Online (Sandbox Code Playgroud)
可悲的是,let绑定的第一部分:
let ok _ = do { print "test2" }
Run Code Online (Sandbox Code Playgroud)
在调用它时不使用 - 并且不强制 - 它的参数,因此忽略"纯"不安全的IO动作.
由于将"纯"值与其构造函数(即())匹配的模式会强制该值,因此如果您编写以下内容,则执行不安全操作:
main = do
() <- return $ unsafePerformIO $ do
print "test2"
print "test"
Run Code Online (Sandbox Code Playgroud)
然后这将工作正常.
还有其他方法可以强制采取行动.你可以明确地模式匹配:
main = do
case unsafePerformIO (print "test2") of
() -> return ()
print "test"
Run Code Online (Sandbox Code Playgroud)
或使用seq如下:
main = do
unsafePerformIO (print "test2") `seq` print "test"
Run Code Online (Sandbox Code Playgroud)
或者像这样:
main = do
unsafePerformIO (print "test2") `seq` return ()
print "test"
Run Code Online (Sandbox Code Playgroud)
或使用严格的评估运算符:
main = do
return $! unsafePerformIO (print "test2")
print "test"
Run Code Online (Sandbox Code Playgroud)
您也可以使用BangPatterns@Chris Stryczynski建议的扩展名.
我不确定哪个是最好的,尽管我倾向于使用($!)运算符作为最惯用的.
正如@Carl所述,出于调试目的,使用tracefrom Debug.Trace通常比unsafePerformIO直接调用更合理,因为它是从纯代码打印调试信息的标准方法,因为实现比简单实现更有思想unsafePerformIO . putStrLn.但是,它可能会出现同样的问题:
import Debug.Trace
main = do
return $ trace "test2" () -- won't actually print anything
print "test"
Run Code Online (Sandbox Code Playgroud)
相反,您需要强制它的值,可能是通过使用上述方法之一:
import Debug.Trace
main = do
return $! trace "test2" () -- with ($!) this works
print "test"
Run Code Online (Sandbox Code Playgroud)
当@Carl说trace有一个可以解决这个问题的API时,他意味着你通常在以下情况下使用跟踪:
let value_i_actually_use = trace "my message" value_of_the_trace_expression
Run Code Online (Sandbox Code Playgroud)
当您实际使用(评估)trace表达式的值时,将显示该消息.
然后