どのような状況liftIO
で使用する必要がありますか?を使用している場合ErrorT String IO
、このlift
関数はIOアクションをに持ち上げるために機能するためErrorT
、liftIO
不要に思えます。
回答:
lift
常に「前の」レイヤーから持ち上げます。2番目のレイヤーから持ち上げる必要がある場合は、以下同様に必要にlift . lift
なります。
一方、liftIO
常にIOレイヤーからリフトします(存在する場合、常にスタックの一番下にあります)。したがって、モナドが2層以上ある場合は、感謝しliftIO
ます。
次のラムダの引数のタイプを比較します。
type T = ReaderT Int (WriterT String IO) Bool
> :t \x -> (lift x :: T)
\x -> (lift x :: T) :: WriterT String IO Bool -> T
> :t \x -> (liftIO x :: T)
\x -> (liftIO x :: T) :: IO Bool -> T
liftIOは、どのモナドを使用していても、IOモナドへのショートカットにすぎません。基本的に、liftIOは可変数のリフトを使用することと同じです。最初は冗長に聞こえるかもしれませんが、liftIOを使用することには、1つの大きな利点があります。IOコードが実際のモナド構造に依存しないため、最終的なモナドが構築されているレイヤーの数に関係なく、同じコードを再利用できます(これは非常に重要です)モナド変換子を書くとき)。
一方、liftIOは、liftのように無料で提供されるわけではありません。使用しているモナド変換子は、それをサポートしている必要があります。たとえば、使用しているモナドはMonadIOクラスのインスタンスである必要がありますが、最近のほとんどのモナドはサポートしています。 (そしてもちろん、タイプチェッカーはコンパイル時にこれをチェックします:それがHaskellの強みです!)
以前の回答はすべて、違いを非常によく説明しています。liftIO
(私のような初心者のハスケラーにとって)魔法のようなものではないことを理解しやすくするために、内部の仕組みに光を当てたかっただけです。
liftIO :: IO a -> m a
ただ上に構築された賢いツールです
lift :: (Control.Monad.Trans.Class.MonadTrans t, Monad m) => m a -> t m a
そして、ほとんどの場合、下のモナドがあるときに使用されますIO
。IO
モナドの場合、その定義は非常に単純です。
class (Monad m) => MonadIO m where
liftIO :: IO a -> m a
instance MonadIO IO where
liftIO = id
その単純な...liftIO
実際id
にはIO
モナドの、基本的IO
に型クラスの定義に含まれる唯一のものです。
問題は、モナド変換子の複数の層で構成されるモナドタイプIO
があるMonadIO
場合、それらのモナド変換子層のそれぞれにインスタンスがある方がよいということです。たとえばMonadIO
、MaybeT m
requiresのインスタンスm
MonadIO
も型クラスがあります。
書くMonadIO
場合は、あまりにも基本的には非常に簡単な作業です。以下のためにMaybeT m
、それは同じように定義されます
instance (MonadIO m) => MonadIO (MaybeT m) where
liftIO = lift . liftIO
または StateT s m
instance (MonadIO m) => MonadIO (StateT s m) where
liftIO = lift . liftIO
それらはすべて同じです。4層の変圧器スタックがある場合、実行する必要があるか、lift . lift . lift . lift $ myIOAction
または単に実行する必要があると想像してくださいliftIO myIOAction
。あなたがそれについて考えるならば、それが定義されている場所lift . liftIO
までずっと掘り下げて、上記の構成されたのと同じコードで終了するまで、すべてがあなたをスタックの1つの層に連れて行きます。IO
liftIO
id
lift
したがって、これが基本的に、変圧器スタックの構成に関係なく、すべての下敷き層がのメンバーでMonadIO
ありMonadTrans
、単一の層で問題がない場合の理由liftIO
です。
liftIO
通常lift
は、十分な場合でもIOレイヤーにリフトするために使用します。