在阅读Haskell上的内容时,我有时会遇到形容词" applicative",但我无法找到这个形容词的足够清晰的定义(而不是比方说,哈斯克尔的Applicative
班。我想学习识别一段代码/算法/数据结构等,即#34; applicative",就像我能识别出一个"递归"。一些对比的例子" applicative"与任何术语打算区别开来的(我希望它本身比#34;非适用的"更有意义的东西)将非常感激。
编辑:例如,为什么单词" applicative"选择命名这个类,而不是其他名字?是什么让这个名称Applicative
非常适合它的类(即使以其默默无闻的代价)?
谢谢!
答案 0 :(得分:21)
在不了解背景的情况下,不清楚“应用”是什么意思。
如果它真的没有引用applicative functor(即Applicative
),那么它可能指的是应用程序本身的形式:f a b c
是一个 applicative 形式,这个应用仿函数的名字来源于:f <$> a <*> b <*> c
是类似的。 (的确,idiom brackets通过让你把它写成(| f a b c |)
来进一步加强这种联系。)
类似地,“应用语言”可以与主要不基于对参数的函数应用(通常以前缀形式)的语言形成对比;例如,连接(“基于堆栈”)语言不适用。
为了回答为什么应用仿函数被称为深度的问题,我建议阅读
Applicative programming with effects;基本思想是很多情况都需要“强化应用程序”之类的东西:在一些有效的上下文中应用纯函数。比较map
和mapM
的这些定义:
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
mapM :: (Monad m) => (a -> m b) -> [a] -> m [b]
mapM _ [] = return []
mapM f (x:xs) = do
x' <- f x
xs' <- mapM f xs
return (x' : xs')
mapA
(通常称为traverse
):
mapA :: (Applicative f) => (a -> f b) -> [a] -> f [b]
mapA _ [] = pure []
mapA f (x:xs) = (:) <$> f x <*> mapA f xs
正如您所看到的,mapA
更简洁,更明显与map
相关(如果您在(:)
中使用map
的前缀形式,则更是如此太)。实际上,即使你有一个完整的Monad
,使用应用函子表示法在Haskell中也很常见,因为它通常要清楚得多。
查看定义也有帮助:
class (Functor f) => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
将(<*>)
的类型与应用类型进行比较:($) :: (a -> b) -> a -> b
。 Applicative
提供的是一种通用的“提升”应用程序形式,使用它的代码是以 applicative 样式编写的。
更正式地说,正如文章中提到并由ertes指出的那样,Applicative
是SK combinators的概括; pure
是K :: a -> (r -> a)
(又名const
)的概括,而(<*>)
是S :: (r -> a -> b) -> (r -> a) -> (r -> b)
的概括。 r -> a
部分简单地推广到f a
;使用Applicative
的{{1}}实例获取原始类型。
实际上,((->) r)
还允许您以更统一的方式编写应用表达式:pure
而不是pure f <*> effectful <*> pure x <*> effectful
。
答案 1 :(得分:15)
在更基础的层面上,可以说“适用”意味着以某种形式的SK微积分工作。这也是Applicative
类的内容。它为你提供了组合子pure
(K的推广)和<*>
(S的推广)。
当您的代码以这种风格表达时,它是适用的。例如代码
liftA2 (+) sin cos
是
的适用表达\x -> sin x + cos x
当然在Haskell中,Applicative
类是应用程序样式编程的主要构造,但即使在monadic或arrowic上下文中,您也可以编写应用程序:
return (+) `ap` sin `ap` cos
arr (uncurry (+)) . (sin &&& cos)
最后一段代码是否具有应用性是有争议的,因为有人可能会认为应用风格需要合理化。