haskell - 理解 haskell 中的 liftM2

标签 haskell io

我很难理解 liftM2 在 haskell 中的工作原理。 我编写了以下代码,但它没有输出任何内容。

import Control.Monad
main = liftM2 (\a b -> putStrLn$show$(+) a b) readLn readLn 

最佳答案

liftM2 的类型入手会有所帮助:

liftM2 :: Monad m => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r

第一个参数是 2 个参数的函数,如 (+)。通常,您会像这样使用 (+):

> 3 + 5
8

但是,您没有两个 Num a => a 类型的值;您正在使用 readLn::Read a => IO a 来获取 Num a => IO a 类型的值。如果您尝试直接添加这些值:

:t (+) readLn readLn
(+) readLn readLn :: (Read a, Num (IO a)) => IO a

它需要IO a才能有一个Num实例。也就是说,您不想添加 readLn; 的返回值。您想要在这些返回值中添加包裹的数字。您可以明确地这样做:

do
 x <- readLn
 y <- readLn
 return $ x + y

或者,您可以“修改”(+) 以隐式解包参数,然后包装结果。这就是 liftM2 的作用:它接受一个 2 参数函数,并将其“提升”到 monad 中,以便它可以处理包装的值。

> :t (+)
(+) :: Num a => a -> a -> a
> :t liftM2 (+)
liftM2 (+) :: (Num r, Monad m) => m r -> m r -> m r

所以 while (+) 3 5::Num a => a, liftM2 (+) $ (return 3) (return 5)::(Monad m, Num a) => m a 。前者的计算结果为 8,后者的计算结果为 return 8(对于特定 monad 的任何 return 操作)。一些非IO示例:

> (liftM2 (+)) (Just 3) (Just 5)
Just 8
> (liftM2 (+)) [3] [5]
[8]
> (liftM2 (+)) (Right 3) (Right 5)
Right 8

liftM2map 非常相似;事实上,liftM(提升 1 个参数函数的版本)只是 map 的另一个名称。

关于haskell - 理解 haskell 中的 liftM2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43781619/

相关文章:

haskell - 如何使用 picosat haskell 绑定(bind)并行运行 SAT 调用?

haskell - 如何在 Haskell 中创建结合状态和错误的 monad

haskell - 使用 postgresql-simple 创建数据库连接时的 GHCI Segfault

c++ - 在 C++ 应用程序的使用中需要对数组、 vector 和映射进行说明

c++ - 与阅读不同格式的数字字符有关的问题

c# - 在 MS Excel 中打开时无法写入文件

haskell - 如何在 Spock 请求处理程序中使用 `IO String`?

haskell - 为什么绑定(bind)到 "unrestricted"类型变量会使变量变得刚性?

c++ - cout on extra thread - 线程安全

java - 未报告的异常 IOException 从 URL 读取文件