0

在 haskell 中,我需要一个全局变量,所以我选择使用 IORef 插槽,这是我的计划:

memo :: IORef Int
memo = unsafePerformIO $ newRefInt 9999

evaluate ARGs s = do
  v <- Right $ unsafePerformIO $ readIORef memo
  val <- Right $ VInt v
  return $ (val, s)

evaluate (Call funcID exp) s = do
...
Right $ writeIORef memo 100
...

我的计划是当执行器评估“调用”节点时,它将参数保存到插槽中。然后,当评估“ARGs”节点时,将读取该备忘录槽。

但无论我做什么,我只能读取 9999 但不能将新值写入该插槽。

即使我尝试过:

memo :: IORef Int
memo = unsafePerformIO $ newRefInt 9999

evaluate ARGs s = do
  Right $ writeIORef memo 100
  v <- Right $ unsafePerformIO $ readIORef memo
  val <- Right $ VInt v
  return $ (val, s)

它仍然会导致备忘录 = 9999。为什么?

4

1 回答 1

12

因为写作也在IO单子中。首先,很多unsafePerformIOs 很糟糕。unsafePerformIO 不应在正常代码中使用

现在,您正在创建一个操作来写入IORef类型为 which的操作,将其IO ()包装在Right构造函数中,然后将其丢弃,您从未真正使用过它。

您也不能unsafePerformIO这样做,因为您对Either构建的值的值并不严格。这就是为什么unsafePerformIO不好,很难推断事情何时/是否会发生。

而是尝试

 evaluate ARGs s = do
    liftIO $ writeIORef memo 100
    v <- liftIO $ readIORef memo
    val <- return $ VInt v
    return $ (val, s)

并使用EitherT单子变换坚持IO在那里。

于 2013-12-04T23:50:22.593 回答