![](/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.