为什么要进行类型检查?

时间:2015-10-14 06:20:02

标签: haskell

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

来自ap的函数Control.Monad具有以下类型:

ap :: Monad m => m (a -> b) -> m a -> m b

这个函数很容易写成:

ap mf mx = do { f <- mf ; x <- mx ; return (f x) }

然后他们写下以下内容:

sequence :: [IO a] → IO [a]
sequence [] = return []
sequence (c : cs) = return (:) `ap` c `ap` sequence cs

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

Maybe a -> (Maybe ([a] -> [a]))的类型ap (:)正如预期的那样,但是类型检查员告诉我(a -> [a]) -> a -> [a]的类型是data.table。这怎么可能?

1 个答案:

答案 0 :(得分:7)

如果你正在写

return (:) `ap` c `ap` sequence cs

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

((return (:)) `ap` c) `ap` (sequence cs)

所以,

(:)                           :: 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]

对于您的第二个问题,ap (:)正在使用Monad实例(->) a,其中

-- Monad instance for ((->) a)
return x = \_ -> x
x >>= f  = \y -> f (x y) y

所以,你有:

ap :: (a -> (b -> c)) -> (a -> b) -> (a -> c)
ap f g = \x -> f x (g x)

如果你只看了ap的do-block定义并扩展了定义。

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