web-dev-qa-db-ja.com

Haskell:lift vs liftIO

どのような状況でliftIOを使用する必要がありますか? ErrorT String IOを使用している場合、lift関数はIOアクションをErrorTに持ち上げるように機能するため、liftIOは不必要に見えます。

77
Lachlan

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
87
Roman Cheplyaka

liftIOは、IOモナド、どちらのモナドでも、どちらでもかまいません。基本的に、liftIOは可変数のリフトを使用することと同じです。最初は冗長に聞こえるかもしれませんが、liftIOを使用すると大きな利点:IOコードは実際のモナド構造に依存しないため、最終的なモナドが構築されているレイヤーの数に関係なく同じコードを再利用できます(これは、モナド変換子)。

一方、liftのようにliftIOは無料ではありません。使用しているモナドトランスフォーマーは、サポートが必要です。あなたがいるモナドはMonadIOクラスのインスタンスでなければなりませんが、ほとんどのモナドは今日そうです(そしてもちろん、タイプチェッカーはコンパイル時にこれをチェックします:それがHaskellの長所です!)。

34
Cristiano Paris