背景
让我们从定义<*> 和pure 作为Applicative 实例的函数开始。对于pure,它将采用任何垃圾值,并返回x。对于<*>,您可以将其视为将x 应用于f,从中获取一个新函数,然后将其应用于g x 的输出。
instance Applicative ((->) r) where
pure x = (\_ -> x)
f <*> g = \x -> f x (g x)
现在,让我们看一下<$> 的定义。它只是fmap 的中缀版本。
(<$>) :: (Functor f) => (a -> b) -> f a -> f b
f <$> x = fmap f x
回想一下fmap 具有以下实现:
instance Functor ((->) r) where
fmap f g = (\x -> f (g x))
证明f <$> x 就是pure f <*> x
让我们从pure f <*> x 开始。将pure f 替换为(\_ -> f)。
pure f <*> x
= (\_ -> f) <*> x
现在,让我们应用<*> 的定义,即f <*> g = \q -> f q (g q)。
(\_ -> f) <*> x
= \q -> (\_ -> f) q (x q)
请注意,我们可以将 (\_ -> f) q 简化为 f。该函数接受我们给它的任何值,并返回f。
\q -> (\_ -> f) q (x q)
= \q -> f (x q)
这看起来就像我们对fmap 的定义!而<$> 运算符只是中缀fmap。
\q -> f (x q)
= fmap f x
= f <$> x
让我们记住这一点:f <$> g 只是 pure f <*> g。
了解(\x y z -> [x, y, z]) <$> (+3) <*> (*2) <*> (/2) $ 5
第一步是重写表达式的左侧以使用<*> 而不是<$>。使用我们在上一节中刚刚证明的内容:
(\x y z -> [x, y, z]) <$> (+3)
= pure (\x y z -> [x, y, z]) <*> (+3)
所以完整的表达式变成了
pure (\x y z -> [x, y, z]) <*> (+3) <*> (*2) <*> (/2) $ 5
让我们使用<*>的定义来简化第一个运算符
pure (\x y z -> [x, y, z]) <*> (+3)
= \a -> f a (g a) --substitute f and g
= \a -> pure (\x y z -> [x, y, z]) a ((+3) a)
现在让我们将pure x 替换为(\_ -> x)。观察a变成了垃圾值,被用作_,被消耗返回函数(\x y z -> [x, y, z])。
\a -> (\_-> (\x y z -> [x, y, z])) a ((+3) a)
= \a -> (\x y z -> [x, y, z]) ((+3) a)
现在让我们回顾一下完整的表达式,然后处理下一个<*>。同样,让我们应用<*> 的定义。
(\a -> (\x y z -> [x, y, z]) ((+3) a)) <*> (*2)
= \b -> (\a -> (\x y z -> [x, y, z]) ((+3) a)) b ((*2) b)
最后,让我们最后一次重复这个最后的<*>。
(\b -> (\a -> (\x y z -> [x, y, z]) ((+3) a)) b ((*2) b)) <*> (/2)
= \c -> (\b -> (\a -> (\x y z -> [x, y, z]) ((+3) a)) b ((*2) b)) c ((/2) c)
请注意,它是一个接受单个值的函数。我们会喂它5。
(\c -> (\b -> (\a -> (\x y z -> [x, y, z]) ((+3) a)) b ((*2) b)) c ((/2) c)) 5
(\5 -> (\b -> (\a -> (\x y z -> [x, y, z]) ((+3) a)) b ((*2) b)) 5 ((/2) 5))
(\b -> (\a -> (\x y z -> [x, y, z]) ((+3) a)) b ((*2) b)) 5 (2.5 )
(\5 -> (\a -> (\x y z -> [x, y, z]) ((+3) a)) 5 ((*2) 5)) (2.5 )
(\a -> (\x y z -> [x, y, z]) ((+3) a)) 5 (10 ) (2.5 )
(\5 -> (\x y z -> [x, y, z]) ((+3) 5)) (10 ) (2.5 )
(\x y z -> [x, y, z]) (8 ) (10 ) (2.5 )
(\x y z -> [x, y, z]) (8) (10) (2.5)
= [8, 10, 2.5]
这就是我们得到最终答案的方式。