関数liftMとmapMの違いは何ですか?
4 に答える
それらは実際には関連していません。それぞれが何をしているのかを説明しようと思います。モナドとは何かについての基本的な理解があると仮定します。
liftM :: Monad m => (a -> b) -> (m a -> m b)
モナドで通常の関数を使用できます。それは function を取り、元の function とまったく同じことをa -> b
行う function に変換しますが、それをモナドで行います。m a -> m b
結果として得られる関数は、モナドに対して何も「実行」しません (元の関数はそれがモナドにあることを知らなかったので、実行できません)。例えば:
main :: IO ()
main = do
output <- liftM ("Hello, " ++) getLine
putStrLn output
この関数("Hello, " ++) :: String -> String
は、文字列の先頭に「Hello,」を追加します。これを に渡すとliftM
、タイプの関数が作成されますIO String -> IO String
。これで、IO モナドで機能する関数ができました。IO は実行しませんが、入力として IO アクションを受け取り、出力として IO アクションを生成できます。したがって、入力として渡すことができgetLine
、それは を呼び出しgetLine
、"Hello" を結果の先頭に追加し、それを IO アクションとして返します。
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
はまったく異なります。liftM
とは異なり、モナド関数を取ることに注意してください。たとえば、IO モナドでは type を持ち(a -> IO b) -> [a] -> IO [b]
ます。これは通常の関数と非常によく似てmap
いますが、モナド アクションをリストに適用し、モナド アクションでラップされた結果リストを生成します。例(かなり悪いもの):
main2 :: IO ()
main2 = do
output <- mapM (putStrLn . show) [1, 2, 3]
putStrLn (show output)
これは以下を出力します:
1
2
3
[(),(),()]
それが行っているのは、リストを反復処理し、リスト(putStrLn . show)
内の各要素に適用し (各数値を出力する IO 効果があります)、数値を()
値に変換することです。結果のリストは次のもので構成されます[(), (), ()]
-- の出力putStrLn
。
まず、タイプが異なります。
liftM :: (Monad m) => (a -> b) -> m a -> m b
mapM :: (Monad m) => (a -> m b) -> [a] -> m [b]
liftM
a -> b
type の関数を対応するモナド
に持ち上げます。mapM
値のリストにモナド値を生成する関数を適用し、モナドに埋め込まれた結果のリストを生成します。
例:
> liftM (map toUpper) getLine
Hallo
"HALLO"
> :t mapM return "monad"
mapM return "monad" :: (Monad m) => m [Char]
...異なることmap
に注意してください。mapM
例えば
> map (x -> [x+1]) [1,2,3]
[[2],[3],[4]]
> mapM (x -> [x+1]) [1,2,3]
[[2,3,4]]
他の回答はすでにそれを十分に説明しているので、型 class のより一般的なバージョンのように、実際の Haskell コードfmap
の代わりに使用されることが通常見られることを指摘します。正常に動作するすべての s も のインスタンスである必要があるため、それらは同等である必要があります。liftM
fmap
Functor
Monad
Functor
演算子<$>
が の同義語として使用されている場合もありますfmap
。
また、mapM f = sequence . map f
、つまり、値のリストをアクションのリストに変換し、アクションを次々と実行して、結果をリストに収集すると考えることができます。
liftM
タイプとmapM
実装からわかるように、これらはまったく異なります。
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
mapM f as = sequence (map f as)
liftM :: (Monad m) => (a1 -> r) -> m a1 -> m r
liftM f m1 = do { x1 <- m1; return (f x1) }
そのためmapM
、リストの各要素にモナド関数を適用しながらliftM
、モナド設定で関数を適用します。