Я не думаю, что определение для SbT
- это то, что вы хотите.Это определяет состав функтора , и, предполагая, что параметр m
равен Functor
или Applicative
, это должно сохранить эти свойства.Но такая композиция, как правило, не создает новую монаду из двух других.См. этот вопрос для получения дополнительной информации по этому вопросу.
Итак, как do вы создаете нужный монадный преобразователь, тогда?В то время как монады не сочиняют напрямую, монады трансформаторы могут быть составлены.Таким образом, чтобы построить новый трансформатор из существующих, вы просто хотите дать название этой композиции.Это отличается от newtype
, который у вас есть, потому что там вы применяете m
напрямую, вместо того, чтобы передавать его в стек трансформаторов.
При определении монадных трансформаторов следует помнить, что ониобязательно работать «задом наперед» определенными способами - когда вы применяете составной трансформатор к монаде, «самый внутренний» трансформатор получает первую трещину в нем, и преобразованная монада, которую он производит, - это то, с чем следующий выходной трансформатор начинает работать, & c,Обратите внимание, что это ничем не отличается от порядка, который вы получаете при применении составной функции к аргументу, например, (f . g . h) x
сначала дает аргумент для h
, даже если f
является «первой» функцией в композиции.
Итак, ваш составной трансформатор должен взять монаду, к которой он применен, и передать ее в самый внутренний трансформатор, который, хм .... ой, получается, что SB
уже уже применяется к монаде.Не удивительно, что это не сработало.Сначала нам нужно это удалить.Где это находится?Не State
- мы могли бы удалить это, но мы не хотим, потому что это часть того, что вы хотите.Хм, но подождите - что опять определяется как State
?Ах да:
type State s = StateT s Identity
Ага, поехали.Давайте вытащим это Identity
оттуда.Мы переходим от вашего текущего определения:
type SB i a = ReaderT ( AlgRO i ) (State ( AlgState i ) ) a
к эквивалентной форме:
type SB i a = ReaderT ( AlgRO i ) ( StateT ( AlgState i ) Identity ) a
Затем выгоняем ленивую задницу:
type SB' i m a = ReaderT ( AlgRO i ) ( StateT ( AlgState i ) m ) a
type SB i a = SB' i Identity a
Но сейчас SB'
выглядит подозрительно, как определение монадного преобразователя, и не без оснований, потому что это так.Итак, мы воссоздаем оболочку newtype
и отбрасываем несколько экземпляров:
newtype SbT i m a = SbT { getSB :: ReaderT ( AlgRO i ) ( StateT ( AlgState i ) m ) a }
instance (Functor m) => Functor (SbT i m) where
fmap f (SbT sb) = SbT (fmap f sb)
instance (Monad m) => Monad (SbT i m) where
return x = SbT (return x)
SbT m >>= k = SbT (m >>= (getSB . k))
instance MonadTrans (SbT i) where
lift = SbT . lift . lift
runSbT :: SbT i m a -> AlgRO i -> AlgState i -> m (a, AlgState t)
runSbT (SbT m) e s = runStateT (runReaderT m e) s
Несколько вещей, на которые следует обратить внимание: функция runSbT
здесь не является полевым средством доступа, а скорее составнойФункция «запустить» для каждого трансформатора в стеке, о котором мы знаем.Точно так же функция lift
должна поднять один раз для двух внутренних трансформаторов, затем добавить заключительную обертку newtype
.Из-за этого они работают как один монадный преобразователь, скрывая тот факт, что это на самом деле составной.
Если вы хотите, то было бы просто написать экземпляры для MonadReader
и MonadState
., подняв экземпляры для составных трансформаторов.