[Haskell] Applicative

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。
pure接受普通类型的值,返回包含这个普通类型值的applicative value。
<*>接受一个包含映射的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是一个多参普通函数,xy...是包含普通值的applicative value,则
pure g <*> x <*> y <*> ... 返回一个applicative value,它包含的值是,g作用于xy...包含的值的结果。

另外,我们看到,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类型表示输出StringIO ()类型表示不输出。
(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)

你可能感兴趣的:([Haskell] Applicative)