为什么我不能将值写入IORef但可以读取它

时间:2013-12-04 23:43:31

标签: haskell interpreter unsafe-perform-io ioref

在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.为什么?

1 个答案:

答案 0 :(得分:12)

因为写作也在IO monad中。首先,很多unsafePerformIO都很糟糕。 unsafePerformIO 不应在普通代码中使用

现在,您正在创建一个操作来写入IORef 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 monad变换将{{1}}粘贴在那里。