Почему я не могу записать значение в 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
...
Мой план - когда исполнитель оценивает узел "Call", он сохраняет параметр в слоте. Затем, когда оценивается узел "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 ответ
Потому что письмо в IO
монада тоже. Во-первых, это много 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
там.