为什么Haskell假定返回的monad类型与作为参数传递的类型相同?

时间:2019-03-25 16:06:37

标签: function haskell types monads

为什么这段代码会编译?

--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没有理由相信它们都引用相同的类型!我想。

但事实并非如此。我在这里想念什么?

1 个答案:

答案 0 :(得分:8)

好吧,让我们看一下do阻止的目标:

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

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

因此,如果elt的类型为m a,很容易看出return (e:sl)(是整个表达式的输出类型)必须具有类型m [a],对于相同的单子m

换句话说,每个do块仅在固定monad的上下文中起作用。

相关问题