簡體   English   中英

如何在`unsafePerformIO`中強制評估IO操作?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM