21

関数liftMとmapMの違いは何ですか?

4

4 に答える 4

35

それらは実際には関連していません。それぞれが何をしているのかを説明しようと思います。モナドとは何かについての基本的な理解があると仮定します。

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

于 2011-05-02T12:00:14.837 に答える
27

まず、タイプが異なります。

liftM :: (Monad m) => (a -> b) -> m a -> m b
mapM :: (Monad m) => (a -> m b) -> [a] -> m [b]

liftMa -> btype の関数を対応するモナド に持ち上げます。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]]
于 2011-05-02T11:56:26.417 に答える
11

他の回答はすでにそれを十分に説明しているので、型 class のより一般的なバージョンのように、実際の Haskell コードfmapの代わりに使用されることが通常見られることを指摘します。正常に動作するすべての s も のインスタンスである必要があるため、それらは同等である必要があります。liftMfmapFunctorMonadFunctor

演算子<$>が の同義語として使用されている場合もありますfmap

また、mapM f = sequence . map f、つまり、値のリストをアクションのリストに変換し、アクションを次々と実行して、結果をリストに収集すると考えることができます。

于 2011-05-02T12:23:49.040 に答える
7

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、モナド設定で関数を適用します。

于 2011-05-02T18:42:41.583 に答える