Непонятное название для запутанного вопроса! Я понимаю: а) монады, б) монаду ввода-вывода, в) монаду Cont ( Control.Monad.Cont ) и г) монаду трансформатора продолжения ContT . (И я смутно понимаю монадные преобразователи в целом - хотя этого недостаточно, чтобы ответить на этот вопрос.) Я понимаю, как написать программу, в которой все функции находятся в монаде Cont (Cont r a
), и я понять, как написать программу, в которой все функции находятся в комбинированной монаде Cont / IO (ContT r IO a
).
Но мне интересно, как написать программу, в которой некоторые функции находятся в комбинированной монаде Cont / IO (ContT r IO a
), а другие функции находятся только в Cont монада (Cont r a
). По сути, я хочу написать всю программу в стиле продолжения, но использовать монаду IO только там, где это необходимо (так же, как в «обычном» коде Haskell, я использую монаду IO только там, где это необходимо).
Например, рассмотрим эти две функции в стиле без продолжения:
foo :: Int -> IO Int
foo n = do
let x = n + 1
print x
return $ bar x
bar :: Int -> Int
bar m = m * 2
Обратите внимание, что foo
требует ввода-вывода, но bar
является чистым. Теперь я понял, как написать этот код полностью, используя монаду продолжения, но мне нужно было также провести IO через bar
:
foo :: Int -> ContT r IO Int
foo n = do
let x = n + 1
liftIO $ print x
bar x
bar :: Int -> ContT r IO Int
bar m = return $ m * 2
Я делаю хочу весь мой код в стиле продолжения, но я не хочу использовать монаду ввода-вывода для функций, которые не требуют этого. По сути, я хотел бы определить bar
следующим образом:
bar :: Int -> Cont r Int
bar m = return $ m * 2
К сожалению, я не могу найти способ вызова функции монады Cont r a
(bar
) из функции монады ContT r IO a
(foo
). Есть ли способ «поднять» не трансформированную монаду в трансформированную? то есть, как я могу изменить строку "bar x
" в foo
, чтобы она могла правильно вызвать bar :: Int -> Cont r Int
?