Поднимите, чтобы зафиксировать * внутреннюю часть * монадного стека трансформаторов.

Предположим, у меня есть IO Int завернутый в StateT MyStateтогда у меня есть значение State MyState Int который я хочу использовать в сложенной монаде. Как мне поднять это в этом внутреннем смысле? Я уже знаю использовать lift или же liftIO если я получаю что-то совместимое с внутренней частью, что мне просто нужно поднять к внешней монаде, но теперь у меня возникает противоположная проблема: значение уже во внешней монаде, но не во внутренней.

Например:

checkSame :: State MyState a -> IO a -> StateT MyState IO Bool
checkSame sim real = do
  rres <- liftIO real
  sres <- ??? sim 
  return $ rres == sres

Должен ли я "получить" состояние, протолкнуть его через runState вручную и собрать все заново, или есть какой-то общий способ сделать это?

Кстати, этот параметр sim - это целая куча функций с состоянием, которые не имеют ничего общего с IO, поэтому я не очень-то хочу заставить их все вернуться StateT MyState IO a если я могу избежать этого.

1 ответ

Решение

У вас есть два варианта:

  1. Найдите морфизм монады. Это часто вопрос поиска правильной библиотеки; в этом случае подъем и обобщение должны привести вас туда, куда вам нужно идти.
  2. Сделай свой State действие более полиморфное. Это обычно используемый и рекомендуемый; это равносильно предварительному применению морфизма из части 1, но в нем уже заложено много механизмов. mtl библиотека, чтобы сделать это легко. Идея в том, что если вы напишите State действие только с точки зрения get, put, а также modifyтогда вместо типа State s aВы можете указать тип:

    MonadState s m => m a
    

    Затем на сайте вызовов вы можете выбрать любую монаду, подходящую для этого, включая State s a а также StateT s IO a, Более того, так как он специализируется на типе State s a, вы можете быть уверены, что это не делает IO или что-нибудь подобное State s a Сам не смог бы сделать, поэтому вы получаете такие же поведенческие гарантии.

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