Если у нас есть следующие две функции, сложение и вычитание, их просто связать в цепочку, чтобы выполнить серию вычислений на входе:
add :: Int -> State Int ()
add n = state $ \x -> ((),x+n)
subtract :: Int -> State Int ()
subtract n = state $ \x -> ((),x-n)
manyOperations :: State Int ()
manyOperations = do
add 2
subtract 3
add 5
--etc
result = execState manyOperations 5
--result is 9
Если мы хотим распечатать состояние после каждого вычисления, мы используем монадный преобразователь StateT
:
add :: Int -> StateT Int IO ()
add n = StateT $ \x -> print (x+n) >> return ((),x+n)
subtract :: Int -> StateT Int IO ()
subtract n = StateT $ \x -> print (x-n) >> return ((),x-n)
manyOperations :: StateT Int IO ()
manyOperations = do
add 2
subtract 3
add 5
main = runStateT manyOperations 5
-- prints 7, then 4, then 9
Можно ли воспроизвести это «комбинированное вычисление и печать» без StateT
или каких-либо пользовательских типов данных?
Насколько я знаю, можно выполнять все процессы, которые MaybeT IO a
может выполнять, используя IO (Maybe a)
, но похоже, что это просто вложенные монады. С другой стороны, у StateT
может не быть альтернативы, потому что s -> (a,s)
принципиально отличается от s -> m (a,s)
.
Я вижу только два направления, в которых может пойти код: использование State Int (IO ())
или IO (State Int ())
, но оба они кажутся бессмысленными, учитывая реализацию StateT
.
Я считаю, что это невозможно. Я прав?
Примечание. Я знаю, что это совершенно непрактично, но я не смог найти решения после нескольких часов работы, что означает, что я прав или моих навыков недостаточно для выполнения задачи.
StateT
. Вы всегда можете просто обойти состояниеInt
явно и делать все только вIO ()
... - person crockeea   schedule 30.01.2015s -> IO (a, s)
напрямую, заменяяa
иs
соответствующим образом. Хотя это точно будет не так красиво. - person David Young   schedule 30.01.2015State
определяется черезStateT
, а не наоборот. - person David Young   schedule 30.01.2015