繁体   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