为什么要进行类型检查?

永劫回*_*劫回帰 1 haskell

我正在阅读文章使用 Conor McBride和Ross Paterson的效果进行Applcative编程,我无法弄清楚为什么他们的第一段代码类型检查.(我有强大的OCaml背景和弱的haskell背景).

有一个函数ap来自Control.Monad以下类型:

ap :: Monad m => m (a -> b) -> m a -> m b
Run Code Online (Sandbox Code Playgroud)

这个函数很容易写成这样:

ap mf mx = do { f <- mf ; x <- mx ; return (f x) }
Run Code Online (Sandbox Code Playgroud)

然后他们写下以下内容:

sequence :: [IO a] ? IO [a]
sequence [] = return []
sequence (c : cs) = return (:) `ap` c `ap` sequence cs
Run Code Online (Sandbox Code Playgroud)

我的问题是我无法弄清楚如何计算(:) `ap` c `ap` sequence cs手工类型,因为它的类型(:)是无处不m (a -> b)在的a -> ([a] -> [a]).

该类型的ap (Just (:))Maybe a -> (Maybe ([a] -> [a])),正如预期,但该typechecker告诉我,类型ap (:)(a -> [a]) -> a -> [a].这怎么可能?

Jus*_* L. 7

如果你在写作

return (:) `ap` c `ap` sequence cs
Run Code Online (Sandbox Code Playgroud)

然后,通过明确的括号,它是

((return (:)) `ap` c) `ap` (sequence cs)
Run Code Online (Sandbox Code Playgroud)

所以,

(:)                           :: a -> [a] -> [a]
return (:)                    :: IO (a -> [a] -> [a])
c                             :: IO a
(return (:)) `ap` c           :: IO ([a] -> [a])
sequence cs                   :: IO [a]
((return (:)) `ap` c) `ap` cs :: IO [a]
Run Code Online (Sandbox Code Playgroud)

对于你的第二个问题,ap (:)是使用Monad实例(->) a,在哪里

-- Monad instance for ((->) a)
return x = \_ -> x
x >>= f  = \y -> f (x y) y
Run Code Online (Sandbox Code Playgroud)

所以你有了:

ap :: (a -> (b -> c)) -> (a -> b) -> (a -> c)
ap f g = \x -> f x (g x)
Run Code Online (Sandbox Code Playgroud)

如果您只是查看了do-block定义ap并扩展了定义.

有可能第二个问题现在可能不会太重要或不重要; 现在关注第一个答案:)