在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.为什么?
答案 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}}粘贴在那里。