应用式函子
在函数式编程中, 应用式函子,或简称应用式(applicative),是在函子和单子之间的中间结构。应用式函子允许函子式计算成为序列(不同于平常函子),但是不允许使用前面计算的结果于后续计算的定义之中(不同于单子)。应用式函子是范畴论中具有张量强度的不严格幺半群函子的编程等价者。
应用式函子是2008年Conor McBride和Ross Paterson在他们的论文《Applicative programming with effects》中介入的[1]。应用式函子在Haskell中最初作为库特征出现,现在已经传播到了其他语言,包括Idris、Agda、OCaml、Scala和F#。为了方便使用应用式函子编程,Glasgow Haskell和Idris二者现在提供了专门设计的语言特征。在Haskell中,应用式函子实现在Applicative
类型类中。
定义
在Haskell中,应用式是参数化类型,被当作这个类型的数据的容器,加上两个方法:pure
和<*>
。考虑一个参数化类型f a
,类型f
的一个应用式的pure
方法有着类型:
pure :: a -> f a
它可被认为是把值带入应用式。类型f
的应用式<*>
方法有着类型:
(<*>) :: f (a -> b) -> f a -> f b
它可被认为是在应用式内部函数应用的等价者[2]。
可作为替代,不提供<*>
,转而提供一个叫做liftA2
的函数。这两个函数都可以依据另一个来定义,因此在极小化完备定义中只需要其中一个[3]。
应用式还要求满足四个方程式定律[3]:
- 同一:
pure id <*> v = v
- 复合:
pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
- 同态:
pure f <*> pure x = pure (f x)
- 互换:
u <*> pure y = pure ($ y) <*> u
所有应用式都是函子。出于明确性,给定方法pure
和<*>
,fmap
可以被实现为[3]:
fmap f x = pure f <*> x
常用的表示法f <$> x
等价于pure f <*> x
。
例子
在Haskell中,Maybe类型可以做成类型类Applicative
的实例,使用下列定义[2]:
instance Applicative Maybe where
-- pure :: a -> Maybe a
pure a = Just a
-- (<*>) :: Maybe (a -> b) -> Maybe a -> Maybe b
Nothing <*> _ = Nothing
_ <*> Nothing = Nothing
(Just g) <*> (Just x) = Just (g x)
如定义章节所述,pure
将一个a
转变成一个Maybe a
,而<*>
应用一个Maybe
函数到一个Maybe
值。对类型a
使用Maybe
应用式,允许在类型a
的值上进行运算,其错误由应用式机制自动处理。例如,要加1
到n :: Maybe Int
,只需要写:
(+1) <$> n
如果n = Nothing
,则结果将是Nothing
;而如果n = Just k
,则结果会是Just (k+1)
。这个例子还展示了应用式如何允许某种泛型函数应用。
参见
引用
- ^ McBride, Conor; Paterson, Ross. Applicative programming with effects. Journal of Functional Programming. 2008-01-01, 18 (1): 1–13. ISSN 1469-7653. doi:10.1017/S0956796807006326.
- ^ 2.0 2.1 Hutton, Bride. Programming in Haskell 2. 2016: 157–163.
- ^ 3.0 3.1 3.2 Control.Applicative. [2021-02-08]. (原始内容存档于2021-03-16).