【问题标题】:Why does Haskell presume the returned monad type is the same type that is passed as an argument?为什么 Haskell 假定返回的 monad 类型与作为参数传递的类型相同?
【发布时间】:2019-08-15 22:32:48
【问题描述】:

为什么这段代码会编译?

--sequence_mine :: Monad m => [m a] -> m [a]
sequence_mine [] = return []
sequence_mine (elt:l) = do
  e <- elt
  sl <- sequence l
  return (e:sl)

注意,我故意在这里注释掉了类型声明。但是即使没有类型声明,代码仍然可以编译并且似乎可以按预期工作 - 这让我感到惊讶。

据我了解,这行应该有歧义:

return (e:sl)

原因是 Haskell 不应该知道我们返回的是哪种类型的 monad。为什么它必须与我们接受的类型相同?

澄清更多。据我了解,如果我没有明确地将类型声明类似于我注释掉的那个,Haskell 应该推断出这个函数有这样的类型:

sequence_mine :: (Monad m1, Monad m2) => [m1 a] -> m2 [a]

除非我明确地将m1m2 统一为m,否则Haskell 没有理由相信它们都指的是同一类型!我想。

然而事实并非如此。我在这里错过了什么?

【问题讨论】:

    标签: function haskell types monads


    【解决方案1】:

    好吧,让我们看看do 块去糖是什么:

    sequence_mine (elt:l) = elt >>= \e -> (sequence l) >>= \sl -> return (e:sl)
    

    回想一下“绑定”运算符&gt;&gt;= 具有类型签名(Monad m) =&gt; m a -&gt; (a -&gt; m b) -&gt; m b。请注意,这里的 monad m 尽管是任意的,但对于参数和结果类型必须相同。

    所以如果eltm a 类型,很容易看出return (e:sl) - 这是整个表达式的输出类型 - 必须有m [a] 类型,对于同一个monad m

    换句话说,每个do 块只能在固定的monad 的上下文中工作。

    【讨论】:

      猜你喜欢
      • 2014-05-13
      • 2013-05-09
      • 1970-01-01
      • 2011-02-20
      • 1970-01-01
      • 1970-01-01
      • 2018-12-24
      • 2021-12-15
      • 2019-12-23
      相关资源
      最近更新 更多