単純なモナドトランスEntityBuilderT
が定義されています。これはちょうどReaderT
より新しいタイプです。 ReaderTを使って単純なnewtypeラッパーにmonad-controlを使用する方法
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
はもちろん、私はモナドの種類もはや一致としてこの機能f
にwithNewSource
を適用することはできません。私はそのようなコンビネータの新しいバージョンを書くためにmonad-control
を使用しようとしました。
これまでに書いたコードを以下に示します。インスタンスの定義はOKのようですが、コンパイラ(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)
あなたの説明は非常に意味があります。ただし、コードはまだです。TypeCheckに失敗: は MonadBaseControl IO IO、依存関係から生じる を組み合わせるために、機能の依存関係を使用して 'M「' EntityBuilderT M0' でタイプ 'IOと一致しませんでした - 中> B」 - > withNewSourceのitemId( 制御の$ \ラン:式で制御 :Control.Monad.Trans.Control ' MonadBaseControl(EntityBuilderT M0)IO、 'コントロールの使用に起因 ' 式で 'でインスタンス宣言liftBase(run m)) – akborder
申し訳ありません!私は私の答えを更新しました。ちなみに、[backticks](http://meta.stackexchange.com/questions/55437/how-can-the-backtick-character-be-included-in-code)を使用して、バッククォートを含むコードの書式を設定することができます。 – ehird