![](/img/trans.png)
[英]If I know (or reasonably expect) that an IO action is referentially transparent, can I use unsafePerformIO on it? Or are there other conditions?
[英]How do I force evaluation of an IO action within `unsafePerformIO`?
import System.IO.Unsafe
main :: IO ()
main = do
_ <- return $ unsafePerformIO $ do
print "test2"
print "test"
上面仅输出test
(通过runghc
运行时),由于Haskell的惰性,我假设第一个IO操作实际上没有得到评估。 如何强制其评估和执行操作?
上面仅用于调试目的。
为了执行IO副作用,需要强制使用unsafePerformIO
创建的“ pure”值(即至少评估为WHNF)。
不幸的是,您的main
功能是:
main = do
_ <- return $ unsafePerformIO $ do
print "test2"
print "test"
将desugars(根据Haskell98报告)分为:
main = let ok _ = do { print "test" }
ok _ = fail "..."
in return (unsafePerformIO (print "test2")) >>= ok
单子法则等效于:
main = let ok _ = do { print "test" }
ok _ = fail "..."
in ok (unsafePerformIO (print "test2"))
可悲的是, let
绑定的第一部分:
let ok _ = do { print "test2" }
不会在调用时使用它的参数,因此也不会强制使用它,因此将忽略“纯”不安全的IO操作。
由于将“ pure”值与其构造函数(即()
)相匹配的模式将强制使用该值,因此如果执行以下操作, 将执行不安全的操作:
main = do
() <- return $ unsafePerformIO $ do
print "test2"
print "test"
那就可以了
还有其他方法可以强制执行此操作。 您可以显式地进行模式匹配:
main = do
case unsafePerformIO (print "test2") of
() -> return ()
print "test"
或使用seq
就像这样:
main = do
unsafePerformIO (print "test2") `seq` print "test"
或像这样:
main = do
unsafePerformIO (print "test2") `seq` return ()
print "test"
或使用严格的评估运算符:
main = do
return $! unsafePerformIO (print "test2")
print "test"
您也可以使用BangPatterns
建议的BangPatterns
扩展名。
我不确定哪个最好,尽管我倾向于使用($!)
运算符作为最惯用的方法。
正如@Carl所指出的,出于调试目的,使用Debug.Trace
trace
通常比直接调用unsafePerformIO
更明智,这是因为这是从纯代码中打印调试信息的标准方式,而且实现比简单简单得多unsafePerformIO . putStrLn
unsafePerformIO . putStrLn
。 但是,它可能会出现相同的问题:
import Debug.Trace
main = do
return $ trace "test2" () -- won't actually print anything
print "test"
相反,您可能需要使用上面的一种方法来强制其值:
import Debug.Trace
main = do
return $! trace "test2" () -- with ($!) this works
print "test"
当@Carl说trace
具有解决此问题的API时,他表示您通常在以下情况下使用跟踪:
let value_i_actually_use = trace "my message" value_of_the_trace_expression
当您实际使用 (评估) trace
表达式的值时,将显示该消息。
接着
以下内容可能有一些限制(在引用答案的注释中提到)。
此处了解更多信息: https : //stackoverflow.com/a/14163739/1663462
{-# LANGUAGE BangPatterns #-}
import System.IO.Unsafe
main :: IO ()
main = do
let !_ = unsafePerformIO $ do
print "test2"
print "test"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.