mgi*_*uca 30

他们并没有真正相关.我会尝试解释他们每个人的作用.我假设您对monad是什么有基本的了解.

liftM :: Monad m => (a -> b) -> (m a -> m b) 让你在monad中使用普通函数.它需要一个函数a -> b,并将其转换为一个函数m a -> m b,它与原始函数完全相同,但它在monad中完成.结果函数不会对monad"做"任何事情(它不能,因为原始函数不知道它是monad).例如:

main :: IO ()
main = do
    output <- liftM ("Hello, " ++) getLine
    putStrLn output
Run Code Online (Sandbox Code Playgroud)

该函数("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,与之不同,它需要一个monadic函数.例如,在IO monad中,它具有类型(a -> IO b) -> [a] -> IO [b].它与普通map函数非常相似,只是它将monadic动作应用于列表,并生成包含在monadic动作中的结果列表.例如(非常糟糕的一个):

main2 :: IO ()
main2 = do
    output <- mapM (putStrLn . show) [1, 2, 3]
    putStrLn (show output)
Run Code Online (Sandbox Code Playgroud)

这打印:

1
2
3
[(),(),()]
Run Code Online (Sandbox Code Playgroud)

它正在做的是迭代列表,应用于列表(putStrLn . show)中的每个元素(具有打印出每个数字的IO效果),并且还将数字转换为()值.结果列表包括[(), (), ()]- 的输出putStrLn.

  • 另外,如果你只关心`mapM`的monadic效果,而不关心返回的列表,你可以使用`mapM_`.`mapM_`函数的类型为`Monad m =>(a - > mb) - > [a] - > m()`,它在putStrLn示例中非常有用,您可能对单元列表不感兴趣. (6认同)
  • @Luke `putStrLn :: String -&gt; IO ()` 返回一个单位值(即 `()`)。这是另一个例子:`mapM (\x -&gt; putStrLn (show x) &gt;&gt; return (x + 1)) [1, 2, 3]`。这将返回一个整数列表而不是单位。 (2认同)

phy*_*nfo 21

首先,类型不同:

liftM :: (Monad m) => (a -> b) -> m a -> m b
mapM :: (Monad m) => (a -> m b) -> [a] -> m [b]
Run Code Online (Sandbox Code Playgroud)

liftM将类型函数a -> b提升为monadic对应项. mapM应用一个函数,该函数为值列表产生monadic值,产生嵌入monad中的结果列表.

例子:

> liftM (map toUpper) getLine
Hallo
"HALLO"

> :t mapM return "monad"
mapM return "monad" :: (Monad m) => m [Char]
Run Code Online (Sandbox Code Playgroud)

...注意map并且mapM有所不同!例如

> map (x -> [x+1]) [1,2,3]
[[2],[3],[4]]
> mapM (x -> [x+1]) [1,2,3]
[[2,3,4]]
Run Code Online (Sandbox Code Playgroud)

  • 在地图的lambda中是`(\ x - > [x + 1])`吗?我尝试了没有反斜杠的语法,我得到了表达式上下文中的`Pattern语法:x - > [x + 1]`.我是一个Haskell新手,所以我可能会在这里遗漏一些东西. (3认同)

ham*_*mar 9

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

您可能还会看到运算符<$>用作同义词fmap.

此外,mapM f = sequence . map f您可以将其视为将值列表转换为操作列表,然后一个接一个地运行操作,将结果收集到列表中.


Don*_*art 5

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) }
Run Code Online (Sandbox Code Playgroud)

因此,mapM将monadic函数liftM应用于列表的每个元素时,在monadic设置中应用函数.