【问题标题】:How does `return` statement have different type than that of a function's definition?`return` 语句的类型与函数定义的类型有何不同?
【发布时间】:2019-06-22 09:15:47
【问题描述】:

在循环中,整数被收集在一个列表中,这些整数的元组是returned。这如何更改为元组列表?

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 是一个函数(和一个虚拟构造函数)。

标签: haskell types type-inference io-monad do-notation


【解决方案1】:

让我们用显式的分隔符重写你的代码,使代码结构更加不言自明:

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 =&gt; [a] -&gt; (a -&gt; m b) -&gt; 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 ~ Intt2 ~ Int,一切都合适。

【讨论】:

    猜你喜欢
    • 2021-02-09
    • 1970-01-01
    • 2020-03-26
    • 2019-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-31
    • 1970-01-01
    相关资源
    最近更新 更多