在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.为什么?
因为写作也在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
monad变换粘IO
在那里.