在一个循环中,整数被收集在一个列表中,并且这些整数的一个元组被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)]
。为什么?
在一个循环中,整数被收集在一个列表中,并且这些整数的一个元组被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)]
。为什么?
让我们用显式的分隔符重写你的代码,使代码结构更加不言自明:
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
there, internaldo
的类型就是IO (t1,t2)
where x :: t1, y :: t2
。所以这也是参与该调用的lambda 函数的返回类型。forM
由于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)]
, 所以 finallyt1 ~ Int
和t2 ~ Int
一切都合适。