gaa*_*kam 5 monads haskell types function
为什么要编译此代码?
--sequence_mine :: Monad m => [m a] -> m [a]
sequence_mine [] = return []
sequence_mine (elt:l) = do
e <- elt
sl <- sequence l
return (e:sl)
Run Code Online (Sandbox Code Playgroud)
注意我在这里特意注释掉了类型声明。但是即使没有类型声明,代码仍然可以编译并且可以按预期工作-这让我感到惊讶。
据我了解,在这方面应该产生歧义:
return (e:sl)
Run Code Online (Sandbox Code Playgroud)
原因是Haskell不应该知道我们要返回哪种类型的monad。为什么它必须与我们接受的类型相同?
要澄清更多。据我了解,如果我不明确地将类型声明与我注释过的类型声明类似,Haskell应该推断该函数具有如下类型:
sequence_mine :: (Monad m1, Monad m2) => [m1 a] -> m2 [a]
Run Code Online (Sandbox Code Playgroud)
除非我明确地统一起来m1
并m2
通过将它们两者都调用m
,否则Haskell没有理由相信它们都引用相同的类型!我想。
但是事实并非如此。我在这里想念什么?
好吧,让我们看一下该do
块可以解决的问题:
sequence_mine (elt:l) = elt >>= \e -> (sequence l) >>= \sl -> return (e:sl)
Run Code Online (Sandbox Code Playgroud)
回想一下,“ bind”运算符>>=
具有类型签名(Monad m) => m a -> (a -> m b) -> m b
。请注意,m
此处的monad 尽管是任意的,但对于参数和结果类型两者都必须相同。
因此,如果elt
具有type m a
,则很容易看到return (e:sl)
-是整个表达式的输出类型- m [a]
对于同一monad 必须具有type m
。
换句话说,每个do
块仅在固定monad的上下文中起作用。
归档时间: |
|
查看次数: |
114 次 |
最近记录: |