class (Functor f) = Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
其中f
并不是一个具体类型,而是一个单参类型构造器(:k f = * -> *
)。f
还必须首先是一个Functor。
类型f a
的值称为applicative value。
<u></u>pure
接受普通类型的值,返回包含这个普通类型值的applicative value。
<u></u><*>
接受一个包含映射的applicative value,返回一个applicative value上的映射。
Applicative Law
(1)pure id <*> v = v
(2)pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
(3)pure f <*> pure x = pure (f x)
(4)u <*> pure y = pure ($ y) <*> u
Examples
(1)Maybe是Applicative类型类的实例
instance Applicative Maybe where
pure = Just
Nothing <*> _ = Nothing
(Just f) <*> somthing = fmap f something
我们看一下<*>
是如何实例化的
(<*>) :: f (a -> b) -> f a -> f b
= Maybe (a -> b) -> Maybe a -> Maybe b
ghci> Just (+ 3) <*> Just 9
Just 12
ghci> pure (+) <*> Just 3 <*> Just 5
Just 8
注:
其中“<*>
”是左结合的。
pure (+) <*> Just 3 <*> Just 5
= (pure (+) <*> Just 3) <*> Just 5
= (Just (+) <*> Just 3) <*> Just 5
= Just (3 +) <*> Just 5
= Just 8
所以,如果g
是一个多参普通函数,x
和y...
是包含普通值的applicative value,则
<u></u>pure g <*> x <*> y <*> ...
返回一个applicative value,它包含的值是,g
作用于x
和y...
包含的值的结果。
另外,我们看到,pure g <*> x = fmap g x
所以,pure g <*> x <*> y <*> ... = fmap g x <*> y <*> ...
我们定义:
(<$>) :: (Functor f) => (a -> b) -> f a -> f b
f <$> x = fmap f x
因此,pure (+) <*> Just 3 <*> Just 5 = (+) <$> Just 3 <*> Just 5
(2)[]是Applicative类型类的实例
instance Applicative [] where
pure x = [x]
fs <*> xs = [f x | f <- fs, x <- xs]
我们看一下<*>
是如何实例化的
(<*>) :: f (a -> b) -> f a -> f b
= [a -> b] -> [a] -> [b]
ghci> [(* 0), (+ 100), (^2)] <*> [1, 2, 3]
[0, 0, 0, 101, 102, 103, 1, 4, 9]
ghci> [(+), (*)] <*> [1, 2] <*> [3, 4]
[4, 5, 5, 6, 3, 4, 6, 8]
其中,
[(+), (*)] <*> [1, 2] <*> [3, 4]
= ([(+), (*)] <*> [1, 2]) <*> [3, 4]
= [(1 +), (2 +), (1 *), (2 *)] <*> [3, 4]
= [4, 5, 5, 6, 3, 4, 6, 8]
(3)IO是Applicative类型类的实例
instance Applicative IO where
pure = return
a <*> b = do
f <- a
x <- b
return (f x)
我们看一下<*>
是如何实例化的
(<*>) :: f (a -> b) -> f a -> f b
= IO (a -> b) -> IO a -> IO b
注:
(1)IO
也是一个单参类型构造器(:k IO = * -> *
)。
(2)IO String
类型表示输出String
,IO ()
类型表示不输出。
(3)()
是一个空tuple类型,这个类型只有一个值,即()
。
所以,()
在不同的上下文中,既可以表示类型,也可以表示值。
(++) <$> getLine <*> getLine
= do
a <- getLine
b <- getLine
return $ a ++ b
其中getLine :: IO String
(4)(->) r是Applicative类型类的实例
instance Applicative ((->) r) where
pure x = \_ -> x
f <*> g = \x -> f x (g x)
我们看一下pure
和<*>
是如何实例化的
pure :: a -> f a
= a -> ((-> r) a)
= a -> (r -> a)
(<*>) :: f (a -> b) -> f a -> f b
= ((->) r (a -> b)) -> ((->) r a) -> ((->) r b)
= (r -> a -> b) -> (r -> a) -> (r -> b)
ghci> (+) <$> (+ 3) <*> (* 100) $ 5
508
pure (+) <*> (+ 3)
= \_ -> (+) <*> (+ 3)
= \x -> (+) ((+ 3) x)
= \x -> ((x + 3) +)
pure (+) <*> (+ 3) <*> (* 100)
= \y -> ((y + 3) +) <*> (* 100)
= \x -> ((x + 3) +) (x * 100)
= \x -> (x + 3) + (x * 100)