-1

在一个循环中,整数被收集在一个列表中,并且这些整数的一个元组被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)]。为什么?

4

1 回答 1

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 Stringthere, 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 ~ Intt2 ~ Int一切都合适。

于 2019-06-22T09:40:16.263 回答