2015-10-14 68 views
1

我正在阅读纸张应用编程效果来自Conor McBride和Ross Paterson,我无法弄清楚为什么他们的第一段代码是typechecks。 (我有很强的OCaml背景和弱的haskell背景)。它为什么会检查和如何?

有一个功能apControl.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 

我的问题是,我不知道如何制定0的类型,因为(:)的类型与m (a -> b)无关,因为它是a -> ([a] -> [a])

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

回答

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 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-块定义并扩大了定义。

很可能现在这个第二个问题可能不会太重要或者不重要;专注于现在的第一个答案:)

+0

感谢您的解释,并指出Monad实例( - >)a'它消除了魔法。 –

相关问题