21

函数 liftM 和 mapM 有什么区别?

4

4 回答 4

35

他们并没有真正的关系。我将尝试解释他们每个人的作用。我假设你对什么是 monad 有一个基本的了解。

liftM :: Monad m => (a -> b) -> (m a -> m b) 允许您在 monad 中使用普通函数。它接受一个 function a -> b,并将其转换为一个 function m a -> m b,这与原始函数完全相同,但在 monad 中完成。结果函数对 monad 没有“做”任何事情(它不能,因为原始函数不知道它在 monad 中)。例如:

main :: IO ()
main = do
    output <- liftM ("Hello, " ++) getLine
    putStrLn output

该函数("Hello, " ++) :: String -> String将“Hello,”添加到字符串中。将它传递给liftM创建一个类型的函数IO String -> IO String——现在你有了一个在 IO monad 中工作的函数。它不做任何 IO,但它可以将一个 IO 动作作为输入,并产生一个 IO 动作作为输出。因此,我可以getLine作为输入传递,它会调用getLine,将“Hello”添加到结果的前面,并将其作为 IO 操作返回。

mapM :: Monad m => (a -> m b) -> [a] -> m [b]完全不同;请注意,与 不同liftM的是,它需要一个单子函数。例如,在 IO monad 中,它的类型为(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]

liftM将类型函数提升a -> b为一元对应物。 mapM将产生单子值的函数应用于值列表,产生嵌入在单子中的结果列表。

例子:

> liftM (map toUpper) getLine
Hallo
"HALLO"

> :t mapM return "monad"
mapM return "monad" :: (Monad m) => m [Char]

...请注意mapmapM有所不同!例如

> 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

其他答案已经很好地解释了它,所以我只想指出你通常会看到fmapused 而不是liftM在真正的 Haskell 代码中,因为fmap它只是 type class 中更通用的版本Functor。由于所有表现良好Monad的 s 也应该是的实例Functor,因此它们应该是等价的。

您可能还会看到运算符<$>用作 的同义词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) }

so while mapM applies a monadic function to each element of a list, liftM applies a function in a monadic setting.

于 2011-05-02T18:42:41.583 回答