Я определил простой монадный преобразователь EntityBuilderT
, который является просто новым типом над ReaderT
.
data EntityBuilderState = ...
newtype EntityBuilderT m a = EntityBuilderT (ReaderT EntityBuilderState m a)
Чтобы обернуть функцию в новую "среду", я написал следующеекомбинатор:
withNewSource :: (Monad m) => String -> EntityBuilderT m a -> EntityBuilderT m a
withNewSource itemId builder = ...
В некоторых случаях я также хочу построить больший стек трансформаторов.Например:
f :: MaybeT (EntityBuilderT m) a
Очевидно, я не могу применить withNewSource
к этой функции f
, поскольку типы монад больше не совпадают.Поэтому я попытался использовать monad-control
для написания новой версии такого комбинатора.
Код, который я написал до сих пор, показан ниже.Хотя с определениями экземпляра все в порядке, компилятор (GHC 7.4.1) отклоняет код со следующим сообщением:
Couldn't match type `IO' with `EntityBuilderT m0'
When using functional dependencies to combine
MonadBaseControl IO IO,
arising from the dependency `m -> b'
in the instance declaration in `Control.Monad.Trans.Control'
MonadBaseControl (EntityBuilderT m0) IO,
arising from a use of `control'
In the expression: control
In the expression: control $ \ run -> withNewSource itemId (run m)
Я несколько растерялся.Кто-нибудь понимает, в чем проблема на самом деле?
{-# LANGUAGE FlexibleInstances, GeneralizedNewtypeDeriving,
MultiParamTypeClasses, TypeFamilies, UndecidableInstances #-}
import Control.Applicative (Applicative)
import Control.Monad (liftM)
import Control.Monad.Base
import Control.Monad.Trans (MonadTrans)
import Control.Monad.Trans.Control
import Control.Monad.Trans.Maybe (MaybeT)
import Control.Monad.Trans.Reader (ReaderT, withReaderT)
data EntityBuilderState
newtype EntityBuilderT m a = EntityBuilderT { unEB :: ReaderT EntityBuilderState m a }
deriving (Applicative, Functor, Monad, MonadTrans)
instance MonadBase b m => MonadBase b (EntityBuilderT m) where
liftBase = liftBaseDefault
instance MonadTransControl EntityBuilderT where
newtype StT EntityBuilderT a = StEB { unStEB :: StT (ReaderT EntityBuilderState) a }
liftWith f = EntityBuilderT $ liftWith $ \run ->
f $ liftM StEB . run . unEB
restoreT = EntityBuilderT . restoreT . liftM unStEB
instance MonadBaseControl b m => MonadBaseControl b (EntityBuilderT m) where
newtype StM (EntityBuilderT m) a = StMT { unStMT :: ComposeSt EntityBuilderT m a }
liftBaseWith = defaultLiftBaseWith StMT
restoreM = defaultRestoreM unStMT
withNewSource :: (Monad m) => String -> EntityBuilderT m a -> EntityBuilderT m a
withNewSource itemId (EntityBuilderT m) = EntityBuilderT (withReaderT undefined m)
withNewSource' :: String -> MaybeT (EntityBuilderT IO) a -> MaybeT (EntityBuilderT IO) a
withNewSource' itemId m = control $ \run -> withNewSource itemId (run m)