我很难理解 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
liftM2
与 map
非常相似;事实上,liftM
(提升 1 个参数函数的版本)只是 map
的另一个名称。
关于haskell - 理解 haskell 中的 liftM2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43781619/