2017-03-21 7 views
3

私はMonadTransのいくつかの事例を見てきましたが、MaybeTの実装は次のようになります。再帰liftIO

instance MonadTrans MaybeT where 
    lift = MaybeT . liftM Just 

私はMonadIOのインスタンスは、内側からリフトの可変数を行うために使用されて理解したようほとんどの場合、IOモナドは直接最外にあります。 MaybeTケースの場合には、次のようになります。

instance (MonadIO m) => MonadIO (MaybeT m) where 
    liftIO = lift . liftIO 

私は理解していないことは、この再帰関数は無限ループを脱出する方法です。ベースケースとは何ですか?

答えて

4

特殊化のための単純な等式推論と書き換え定義が役に立ちます。 MonadIOの基本ケースはIOです。 MaybeTはモナド変圧器なので、簡単な例ではMaybeTIOを組み合わせることができます。

ここでは、この関数定義を、質問から段階的に適用して書き直してみましょう。

foo 
= liftIO {- for MaybeT -} getLine 
= lift (liftIO {- for IO here -} getLine) -- step 2 
= lift (id getLine) 
= lift getLine 
= MaybeT (liftM Just getLine) 
  1. getLineIO String
  2. liftM Just getLine型を持つIO (Maybe String)
  3. MaybeT m aコンストラクタ型を持つ私たちのケースでm = IOa = Stringタイプm (Maybe a)の値を必要とします。分析する

おそらく最も困難なステップは、ステップ2である。しかし、あなたが自分でliftIO :: IO a -> m alift :: Monad m => m a -> t m aの種類を思い出させる場合、現実にはそれは非常に簡単です。したがって、すべての作業は型推論によって行われます。

5

おそらく驚くべきことに、以下の定義は、見た目が変わっても、再帰的であると思われます。

instance (MonadIO m) => MonadIO (MaybeT m) where 
    liftIO = lift . liftIO 

右側liftIOmモナドためliftIOである左側のliftIOは、MaybeT mモナドためliftIOからです。

したがって、これは別のモナドのliftIOに関して1つのモナド内にliftIOを単純に定義します。再帰はありません。

これは、たとえば

instance (Show a, Show b) => Show (a,b) where 
    show (x,y) = "(" ++ show x ++ ", " ++ show y ++ ")" 

上記では、コンポーネントの印刷方法に応じてペアを印刷する方法を定義しています。それは再帰的に見えますが、実際にはそうではありません。これは、明示的な型の引数を挿入することで、これを可視化する助けることができる

、少なくとも精神的に:今

-- pseudo-code 
instance (Show a, Show b) => Show (a,b) where 
    show @(a,b) (x,y) = 
     "(" ++ show @a x ++ ", " ++ show @b y ++ ")" 

show @(a,b)show @a、およびshow @bは異なる機能です。