SbT
の定義があなたの望むものだとは思いません。これは、ファンクタの構成を定義し、m
パラメータがFunctor
またはApplicative
であると仮定すると、これらのプロパティは保持されます。しかし、そのような構成は、一般に、2つのうちの新しいモナドを作成しません。その件については、this questionを参照してください。
だから、どのようにを実行しますか?あなたは、あなたが望むモナドトランスを作成しますか?モナドは直接作成しませんが、モナド変圧器を構成することができます。だから、既存のトランスフォーマーから新しいトランスを構築するには、基本的にそのコンポジションに名前を付けるだけです。これはnewtype
とは異なり、m
をトランススタックに渡すのではなく、直接適用しているためです。
モナド変圧器の定義については、コンポジットトランスをモナドに適用すると、「最も内側の」変圧器が最初の亀裂を取得し、それが生成する変換されたモナドは、次のトランスフォーマーが動作するようになったものです。& c。これは、作成された関数を引数に適用するときに得られる順序とまったく同じではないことに注意してください。 (f . g . h) x
は、最初にh
に引数を与えますが、f
はコンポジションの最初の関数です。
わかりましたが、ので、あなたの複合トランスは、それが適用されますモナドを取ると、オム....おっと、SB
はモナドに適用すでにであることが判明している最も内側の変圧器、にそれを渡す必要があります。これがうまくいかないのも不思議ではない。最初にそれを削除する必要があります。それはどこにある? State
--we それを削除することはできますが、それはあなたが望むものの一部なので、望みたくありません。うーん、しかし、待ってください - 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
ラッパーを再作成し、そこにいくつかのインスタンスを放り出す:各ここrunSbT
機能は、フィールドアクセサではなく、構成「実行」機能:
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
のノートを取るためにカップルの事を私たちが知っているスタックの変圧器。同様に、lift
関数は、2つの内部トランスのために一度持ち上げてから、最後のnewtype
ラッパーを追加する必要があります。これらの両方は、モナド変圧器として機能し、実際にコンポジットであることを隠しています。
希望する場合は、構成されたトランスのインスタンスを持ち上げて、MonadReader
とMonadState
のインスタンスを作成するのは簡単です。
これが実行されます。ありがとう! – dsign