应用函子是众所周知的,并且在Haskellers中广受欢迎,因为它们能够在有效的环境中应用函数.
在类别理论术语中,可以证明以下方法Applicative:
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)
相当于有一个Functor f操作:
unit :: f ()
(**) :: (f a, f b) -> f (a,b)
Run Code Online (Sandbox Code Playgroud)
这个想法是写pure你只是用给定的值替换()in unit,并写(<*>)你将函数和参数压缩到一个元组,然后在它上面映射一个合适的应用程序函数.
此外,这种对应关系变成了Applicative法律成左右自然monoidal十岁上下的法律unit和(**),所以实际上是一个适用函子也恰恰是一类理论家称之为一个宽松monoidal仿函数(松懈,因为(**)仅仅是一个自然的转变,而不是同构).
好的,很好,很棒.这是众所周知的.但是,这只是一个家庭不严monoidal函子-那些尊重的monoidal结构产品.松散的幺正算子涉及两种幺半群结构的选择,在源头和目的地:如果你把产品变成总和,你就会得到:
class PtS f where
unit :: f Void
(**) :: f a -> f b -> f (Either a b) …Run Code Online (Sandbox Code Playgroud) 我正在玩pure和liftA2(以及(<*>) = liftA2 id成为派生组合者)制定Applicative .
我可以想到一堆候选法则,但我不确定最小集合是什么.
f <$> pure x = pure (f x)f <$> liftA2 g x y = liftA2 ((f .) . g) x yliftA2 f (pure x) y = f x <$> yliftA2 f x (pure y) = liftA2 (flip f) (pure y) xliftA2 f (g <$> x) (h <$> y) = liftA2 (\x y -> f (g x) (h y)) x y如适用函数的黑客中提到的那样,它们是强大的松散单曲面函数。那么,为什么它们在Haskell中的定义却不这样显示:
class Functor f => MonoidalApplicative f where
mult :: f a -> f b -> f (a,b)
unit :: a -> f a
starAp :: f (a -> b) -> f a -> f b
starAp h x = fmap (uncurry ($)) (mult h x)
Run Code Online (Sandbox Code Playgroud)
<*>(starAp)可以很容易地按照乘法来重构,这个定义对我来说更简单。例如,这是Maybe实例:
instance MonoidalApplicative Maybe where
mult (Just x) (Just y) = Just (x,y)
mult _ _ = Nothing
unit x = Just x
Run Code Online (Sandbox Code Playgroud)