我很难理解liftM2
在haskell中的工作原理。 我写了下面的代码,但它不输出任何东西。了解haskell中的liftM2
import Control.Monad
main = liftM2 (\a b -> putStrLn$show$(+) a b) readLn readLn
我很难理解liftM2
在haskell中的工作原理。 我写了下面的代码,但它不输出任何东西。了解haskell中的liftM2
import Control.Monad
main = liftM2 (\a b -> putStrLn$show$(+) a b) readLn readLn
我不认为编译器可以解析这个没有空格$
左右。然后,这里主要有类型IO(IO())
如果你想总结“内部”IO,你可以使用liftM2 (+)
,然后打印结果。
例如:
main :: IO()
main = print =<< liftM2 (+) readLn readLn
或者用做记号:
main :: IO()
main = do
s <- liftM2 (+) readLn readLn
print s
它有助于先从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
因此,尽管(+) 3 5 :: Num a => a
,liftM2 (+) $ (return 3) (return 5) :: (Monad m, Num a) => m a
。前者评估为8
,后者为return 8
(无论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
的另一个名称。
好的,我们如何使用'liftM2'来读取两个整数并打印它们的总和? –
只是编辑我的答案添加此。 –
当'-XTemplateHaskell'处于活动状态时,不带空格的'$'只是一个问题。但是,可能总是在它周围留出空间是一个好主意,这样,如果您以后需要使用TH,则不必担心它。无论如何,'$'是一个非常“太空”的操作符,它的优先级低。 – leftaroundabout