Я структурирую вычисления вокруг использования монады RWS
(Reader
+Writer
+State
):
newtype Problem a = Problem { unProblem :: RWS MyEnv MyLog MyState a }
deriving ({- lots of typeclasses -})
Вычисление строится шаг за шагом путем сборки элементарных вычислений вида
foo :: a -> Problem b
Однако иногда подвычислениям не требуется полная мощность монады RWS
. Например, рассмотрим
bar :: c -> State MyState d
Я хотел бы использовать bar
как часть более крупного вычисления в контексте монады Problem
. Я вижу три способа сделать это, ни один из которых не кажется мне очень элегантным.
Вручную распаковать вычисление
State
и перепаковать его в монаду RWS:baz :: a -> RWS MyEnv MyLog MyState c baz x = do temp <- foo x initialState <- get let (finalResult, finalState) = runState (bar temp) initialState put finalState return finalResult
Измените сигнатуру типа
bar
, подняв ее в монадуProblem
. Недостатком этого является то, что сигнатура нового типа явно не обещает, чтоbar
не зависит отMyEnv
, и ничего не записывает вMyLog
.Замените монаду
RWS
явным стеком монадReaderT MyEnv WriterT MyLog State MyState
. Это позволяет мне сжатоlift.lift
вычислитьbar
в полную монаду; однако этот трюк не сработает, например. для подвычисления формыc -> Reader MyEnv d
.
Есть ли более чистый способ составить foo
и bar
? У меня есть подозрение, что несколько умных определений экземпляров классов типов могли бы помочь, но я не вижу, как именно действовать дальше.
mtl
. На самом деле я не знал оtransformers
. - person Arek' Fu   schedule 29.08.2016