我很難理解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