私が機能を持っているとしましょう
f :: State [Int] Int
および関数:
g :: StateT [Int] IO Int
f
で使用してg
、それらの間の状態を渡したいです。のライブラリ関数はあり
StateT (return . runState f)
ますか?または、一般的に、対応するモナドを持つモナド変換子が与えられた場合、そのためのライブラリ関数はありますか?
私が機能を持っているとしましょう
f :: State [Int] Int
および関数:
g :: StateT [Int] IO Int
f
で使用してg
、それらの間の状態を渡したいです。のライブラリ関数はあり
StateT (return . runState f)
ますか?または、一般的に、対応するモナドを持つモナド変換子が与えられた場合、そのためのライブラリ関数はありますか?
さらに一般的には、トランスフォーマースタックの内層に変換を適用しようとしています。2つの任意のモナドの場合、型アノテーションは次のようになります。
fmapMT :: (MonadTrans t, Monad m1, Monad m2) => (m1 a -> m2 a) -> t m1 a -> t m2 a
基本的に高レベルfmap
。実際、最終的なパラメーターのマップと組み合わせることは、おそらくさらに理にかなっています。
fmapMT :: (MonadTrans t, Monad m1, Monad m2) => (m1 a -> m2 b) -> t m1 a -> t m2 b
明らかに、これがすべての場合に可能になるわけではありませんが、「ソース」モナドIdentity
の方が簡単である可能性がありますが、それが機能する場所に別のタイプクラスを定義することを想像できます。典型的なモナド変換子ライブラリには、このようなものはないと思います。ただし、ハッキングを閲覧すると、Monatron
パッケージ内で非常によく似たものが見つかります。
class MonadT t => FMonadT t where
tmap' :: FunctorD m -> FunctorD n -> (a -> b)
-> (forall x. m x -> n x) -> t m a -> t n b
tmap :: (FMonadT t, Functor m, Functor n) => (forall b. m b -> n b)
-> t m a -> t n a
tmap = tmap' functor functor id
の署名でtmap'
は、タイプは基本的に、インスタンスを直接使用するのではなく、FunctorD
アドホックな実装です。fmap
Functor
また、2つのFunctorのような型コンストラクターFとGの場合、のような型の関数はFからGへの自然変換(forall a. F a -> G a)
を記述します。パッケージのどこかに必要なトランスフォーマーマップの別の実装がある可能性がありますが、よくわかりません。モナド変換子の圏論的バージョンはどうなるので、それが何と呼ばれるのかわかりません。category-extras
インスタンス(いずれかが持つ必要があります)と自然変換tmap
のみが必要であり、はによって提供されるモナドからの自然変換があるため、必要な関数は 、「基本的な」モナドがとにかく、に適用されるトランスフォーマーの同義語として定義されます。これは、トランスフォーマーライブラリの場合に一般的に当てはまります。Functor
Monad
Monad
Identity
return
FMonadT
tmap (return . runIdentity)
Identity
特定の例に戻ると、Monatronには実際にFMonadT
forのインスタンスがあることに注意してくださいStateT
。
あなたが求めているのは、モナドからへのマッピング(モナド射として知られている)StateT m
ですStateT n
。私はmmorph
ライブラリを使用します。これは、モナド射を操作するための非常に優れたツールのセットを提供します。
State -> StateT m
探している変換を実行するために、にIdentity
埋め込まれたモナドを一般化する射を定義することから始めます。State
generalize :: Monad m => Identity a -> m a
generalize = return . runIdentity
次に、この射を持ち上げて、の内側のモナドに作用させますStateT
。つまり、あるモナドから別のモナドへのマッピングを与える関数(たとえば、generalize
射)が必要であり、モナド変換子のベースモナドに作用する関数を与えt Identity a -> t m a
ます。これはのクラスのhoist
関数に似ていることがわかります。mmorph
MFunctor
hoist :: Monad m => (forall a. m a -> n a) -> t m b -> t n b
ピースをまとめて、
myAction :: State s Int
myAction = return 2
myAction' :: Monad m => StateT s m Int
myAction' = hoist generalize myAction
このような関数は、すべてのモナド変換子に対して定義できるわけではありません。Cont r
たとえば、モナドを持ち上げることはできません。これはContT r IO
、IOモナド(a -> IO r
)の継続を純粋な継続()に変換する必要があるためですa -> r
。