Почему я не могу записать значение в 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 там.

Другие вопросы по тегам