在一个循环中,整数被收集在一个列表内,并且这些整数的元组被return
加起来。这如何更改为元组列表?
input :: IO [(Int,Int)]
input = do
n <- readLn :: IO Int
forM [1..n] $ \_ -> do
[x,y] <- map read . words <$> getLine
return (x,y)
我期望值的类型为(Int,Int)
,但它为[(Int,Int)]
。为什么?
答案 0 :(得分:4)
让我们使用显式分隔符重新编写代码,使代码结构更加自如:
input :: IO [(Int,Int)]
input = do {
n <- readLn ;
forM [1..n] (\ _ -> do {
[x,y] <- fmap (map read . words) getLine ;
return (x,y) })
}
因此return (x,y)
属于内部do
。
因为那里有一个getLine :: IO String
,所以内部do
的类型是IO (t1,t2)
,其中x :: t1, y :: t2
。因此,这也是参与forM
调用的 lambda函数的返回类型。
自forM :: Monad m => [a] -> (a -> m b) -> m [b]
起,我们在这里知道m ~ IO
,我们得出了总体do
的最后一个表达式的类型为
forM :: [a] -> (a -> IO b) -> IO [b]
,因此根据该IO [b] ~ IO [(t1,t2)]
表达式,自b ~ (t1,t2)
以来,总体类型为return
。
lambda函数返回IO b
,因此forM
返回IO [b]
,与上面的类型相同。 do
块的类型与其最后一个表达式的类型相同。
该函数的签名说它是IO [(Int,Int)]
,所以最终t1 ~ Int
和t2 ~ Int
都适合了。