Reputation: 17
In haskell, I need a global variable so I choose to use IORef slot, here is my plan:
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
...
My plan is when the executer evaluates the "Call" node, it will save the parameter into the slot. Then when the "ARGs" node are evaluated, that memo slot would be read.
But whatever I do, I just can read 9999 but cannot write a new value into that slot.
Even I tried:
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)
It will still result that memo = 9999. Why?
Upvotes: 0
Views: 329
Reputation: 53881
Because writing is in the IO
monad too. First off, that many unsafePerformIO
s is just bad. unsafePerformIO
should not be used in normal code.
Right now, you're creating an action to write to the IORef
which is of type IO ()
, wrapping it up in the Right
constructor, and then throwing it away, you never actually use it.
You can't unsafePerformIO
it either since you're not strict in the value of the Either
value you constructed. This is why unsafePerformIO
is bad, it's incredibly hard to reason about when/if things are going to happen.
Instead try
evaluate ARGs s = do
liftIO $ writeIORef memo 100
v <- liftIO $ readIORef memo
val <- return $ VInt v
return $ (val, s)
And use the EitherT
monad transform to stick IO
in there.
Upvotes: 12