Haskell中的liftM和mapM有什么区别

发布于 2024-11-05 04:50:28 字数 27 浏览 1 评论 0原文

liftM 和mapM 函数有什么区别?

What is the difference between the functions liftM and mapM?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

故人爱我别走 2024-11-12 04:50:28

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

liftM :: Monad m =>; (a→b)→ (ma -> mb) 允许您在 monad 中使用普通函数。它需要一个函数 a ->; b,并将其转换为函数ma -> 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→mb)→ [一]-> m [b] 是完全不同的;请注意,与 liftM 不同,它采用一元函数。例如,在 IO monad 中,它的类型为 (a -> IO b) -> [一]-> IO [b]。它与普通的 map 函数非常相似,只是它将单子操作应用于列表,并生成包装在单子操作中的结果列表。例如(一个非常糟糕的例子):

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

它打印:

1
2
3
[(),(),()]

它所做的是迭代列表,将 (putStrLn . show) 应用于列表中的每个元素(具有打印出每个元素的 IO 效果)数字),并将数字转换为 () 值。结果列表由 [(), (), ()] 组成 - putStrLn 的输出。

They aren't really related. I'll try to explain what each of them does. I assume you have a basic understanding of what a monad is.

liftM :: Monad m => (a -> b) -> (m a -> m b) lets you use an ordinary function in a monad. It takes a function a -> b, and turns it into a function m a -> m b, that does exactly the same thing as the original function, but does it in a monad. The resulting function doesn't "do" anything to the monad (it can't, because the original function didn't know it was in a monad). For example:

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

The function ("Hello, " ++) :: String -> String prepends "Hello, " to a string. Passing it to liftM creates a function of type IO String -> IO String -- now you have a function that works in the IO monad. It doesn't do any IO, but it can take an IO action as input, and produces an IO action as output. Therefore, I can pass getLine as input, and it will call getLine, prepend "Hello, " to the front of the result, and return that as an IO action.

mapM :: Monad m => (a -> m b) -> [a] -> m [b] is quite different; note that unlike liftM, it takes a monadic function. For example, in the IO monad, it has type (a -> IO b) -> [a] -> IO [b]. It is very much like the ordinary map function, only it applies a monadic action to a list, and produces a result list wrapped in a monadic action. For example (a pretty bad one):

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

This prints:

1
2
3
[(),(),()]

What it is doing is iterating over the list, applying (putStrLn . show) to each element in the list (having the IO effect of printing out each of the numbers), and also transforming the numbers into the () value. The resulting list consists of [(), (), ()] -- the output of putStrLn.

挽清梦 2024-11-12 04:50:28

首先,类型不同:

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]]

First, the types differ:

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

liftM lifts a function of type a -> b to a monadic counterpart.
mapM applies a function which yields a monadic value to a list of values, yielding list of results embedded in the monad.

Examples:

> liftM (map toUpper) getLine
Hallo
"HALLO"

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

... note that map and mapM differ! E.g.

> map (x -> [x+1]) [1,2,3]
[[2],[3],[4]]
> mapM (x -> [x+1]) [1,2,3]
[[2,3,4]]
我爱人 2024-11-12 04:50:28

其他答案已经解释得很好,所以我只想指出,在真正的 Haskell 代码中,您通常会看到使用 fmap 而不是 liftM,如 fmap< /code> 只是类型类Functor 中更通用的版本。由于所有行为良好的 Monad 也应该是 Functor 的实例,因此它们应该是等效的。

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

另外,mapM f = 序列。 map f,因此您可以将其视为将值列表转换为操作列表,然后依次运行操作,将结果收集到列表中。

The other answers have already explained it well, so I will just point out that you will usually see fmap used instead of liftM in real Haskell code, as fmap is just a more general version in the type class Functor. As all well-behaved Monads should be instances of Functor as well, they should be equivalent.

You may also see the operator <$> used as a synonym for fmap.

Also, mapM f = sequence . map f, so you can think of it as turning a list of values into a list of actions, and then running the actions one after another, collecting the results in a list.

挽你眉间 2024-11-12 04:50:28

liftMmapM 非常不同,您可以通过它们的类型和实现看到这一点:

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 在一元设置中应用一个函数。

liftM and mapM are quite different, as you can see via their types and their implementation:

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文