Why I can't write a value into the IORef but can read it

322 views Asked by At

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?

1

There are 1 answers

1
daniel gratzer On

Because writing is in the IO monad too. First off, that many unsafePerformIOs 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.