我正在阅读来自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
。这怎么可能?
答案 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定义并扩展了定义。
有可能第二个问题现在可能不会太重要或太重要;现在关注第一个答案:)