2011-07-06 16 views
5

これは問題です。私は持っています:mapMonadTrans :: MonadTrans xT =>(m a - > n b) - > xT m a - > xT n b

f :: MonadIO m => ReaderT FooBar m Answer; 
f = (liftIO getArgs) >>= ... 

私はこれを修正された引数で実行する必要があります。 mが不明であるため、私はすべてのmについてメートルに(WITHARGSの引数)を形質転換するために何らかの形で必要なので、私は単に

mapReaderT (withArgs args) :: ReaderT r IO b -> ReaderT r IO b 

を使用することはできません。

私が見つけた一つの可能​​性は、このように、私自身のWITHARGSを定義することです:

import System.Environment (setArgs, freeArgv); 
withArgv new_args act = do { 
    pName <- liftIO System.Environment.getProgName; 
    existing_args <- liftIO System.Environment.getArgs; 
    bracket (liftIO $ setArgs new_args) 
      (\argv -> do { 
         _ <- liftIO $ setArgs (pName:existing_args); 
         liftIO $ freeArgv argv; 
        }) 
      (const act); 
}; 

withArgs xs act = do { 
    p <- liftIO System.Environment.getProgName; 
    withArgv (p:xs) act; 
}; 

しかし、これはその場しのぎの、そして一つの機能に固有のものです - 私はへの再書き込みごとwithX :: X -> IO a -> IO a、例えば必要があるだろうControl.Exception.handle

もしあれば、これを行うより良い方法は何ですか?

編集:ハンドルの場合は、Control.Monad.CatchIOが見つかりました。他のケースでは、私は上記のkludgeを避けるために、もう一つの簡潔なkludge(投稿する価値はない)を使用しました。それでももっと良い解決策を模索しています!

+0

'f'でタイプシグネチャを削除するとどうなりますか?私は 'MonadIO'への制約があまりにも制限されているのだろうかと思います。 –

+0

私は 'f'でI/Oをする必要があります。さもなければ、それは壮大になるでしょう。 (実際には、型bの値を返すための関数を持つデータ型aがあり、その型はa型の値の一部がI/Oを使ってbを生成できるほど一般的でなければなりません) –

+0

@strake :Control.Monad.CatchIOに問題があることに注意してください。つまり、短絡モナド変圧器(たとえばErrorT)を使用している場合、予想どおりに動作しない可能性があります。これが設計上の欠陥であるか誤用であるかは、解釈が可能ですが、それを認識しておく必要があります。詳細については、http://andersk.mit.edu/haskell/monad-peel/を参照してください。 –

答えて

4

monad-controlパッケージでこれを行います。私はあなたが関数liftIOOp_Control.Monad.IO.Controlから欲しいと思います。

具体的には、

liftIOOp_ (withArgs newArgs) f 

は、あなたが欲しいものを行う必要があります。 liftIOOp機能を使用すると、bracketのようなものも持ち上げることができます。

+0

エース!ちょうど私が必要なもの。ありがとう! –

4

私はinterleavableIO packageがこの問題を解決すると信じています。それはthis cafe threadで議論されています。

+0

残念ながら、それは非常に困惑しているかもしれません。どのように使用されていますか? –

+0

@strake、残念ながら、私はそれを使ったことはありません、私はそれが議論されていることを思い出しました。たぶん別のSOの質問は順序ですか? – luqui

8

あなたが探しているのは、モナドの準同型性をモナド変圧器に吊り上げることです。 nからmからモナドの準同型f与えられた、と言うことです

class MonadHoist t where 
    hoist :: (Monad m, Monad n) => (forall a. m a -> n a) -> t m a -> t n a 

    t :: Monad m => t Identity a -> t m a 
    t = hoist (return . runIdentity) 

は、あなたはホイストを使用してt nt mからモナドの準同型を得ることができます。

モナド準同型性は、上記のタイプよりもやや強く、モナド法を維持する責任があります。

f . return = return 
f . fmap g = fmap g . f 
f . join = join . f . fmap f 
     = join . fmap f . f -- by the second law 
     = (>>= f) . f  -- >>= in terms of join 

お知らせ私はhoistMonadHoistの種類に潜入数量詞は、ほぼすべてのインスタンスのためにその柔軟性を必要とすることが判明! (Readerは、そうでない場合に起こります。それなしでMaybeTを書き込もうとしてください)

一般に、モナドトランスはこのクラスをインスタンス化できます。例えば:

instance MonadHoist (StateT s) where 
    hoist f (StateT m) = StateT (f . m) 

instance MonadHoist (ReaderT e) where 
    hoist f (ReaderT m) = ReaderT (f . m) 

instance MonadHoist MaybeT where 
    hoist f (MaybeT m) = MaybeT (f m) 

それはRank2Typeを必要とするので、私たちは現在、transformersmtlパッケージでそれを提供していないが、実装が非常に簡単です。

十分な需要がある場合は、monad-extrasパッケージに喜んでパッケージ化します。

これはあなたの投稿のトピックのタイプによって与えられた質問に答えているのですが、あなたの質問に関連するテキストの大部分が反映している必要性には言及していないので、

そのためには、luquiのアドバイスに従ってください。 =)

+0

良いアイデア。実際には(私が気づいたように)他の誰かがそれを認識しました:http://hackage.haskell.org/package/mmtl –

0

それだけでなく、あなたが欲しい効果を得るためにrunReaderTを使用することができそうです:

*> :t withArgs [] (runReaderT f FooBar) 
withArgs [] (runReaderT f FooBar) :: IO Answer 
FooBarは、いくつかのデータコンストラクタです

fは、上記のように定義されます。

関連する問題