Haskell:<*>的发音是什么?[关闭]


109

您如何在Applicative类型类中发音这些函数:

(<*>) :: f (a -> b) -> f a -> f b
(*>)  :: f a -> f b -> f b
(<*)  :: f a -> f b -> f a

(也就是说,如果他们不是操作员,那么他们会被称为什么?)

附带说明一下,如果您可以将其重命名pure为对非数学家更友好的名称,您会怎么称呼它?


6
@J Cooper ...您能听到我们的发音吗?:)您可能想在meta.stackoverflow.com上发布一个请求,以获取语音记录和播放功能:)。
基里尔

8
的发音是:“真心的悲伤,他们真的没钱了,不是吗?” 另外,的好名字pure可能是makeApplicative
Chuck

@Lirik,好吧,我想发音是“ whaddya称呼这件事” :) @Chuck,发表您的pure建议作为答案,我会投票给您
J Cooper 2010年

6
(<*>)是Control.Monad的Control.Applicative版本的“ ap”,因此“ ap”可能是最合适的名称。
爱德华·KMETT

11
我会称它为独眼巨人,但这就是我。
RCIX

Answers:


245

抱歉,我不是很了解我的数学知识,所以我很好奇如何在Applicative类型类中发音这些函数

我认为,是否了解您的数学与这里无关。您可能已经知道,Haskell从抽象数学的各个领域中借用了一些术语,最著名的是范畴论,从中我们得到了函子和单子。在Haskell中,这些术语的使用与形式上的数学定义有所不同,但是无论如何它们通常足够接近以至于是好的描述性术语。

Applicative类型的类位于介于FunctorMonad,所以人们期望它有一个类似的数学基础。该Control.Applicative模块的文档开始于:

该模块描述了函子和monad之间的中间结构:它提供纯表达和排序,但不提供绑定。(从技术上讲,是一个强大的松散单曲面函子。)

class (Functor f) => StrongLaxMonoidalFunctor f where
    . . .

Monad我想不像它那么吸引人。

所有这些基本上可以归结为Applicative与任何在数学上特别有趣的概念都不对应,因此周围没有现成的术语可以捕捉其在Haskell中的使用方式。因此,暂时搁置数学。


如果我们想知道该叫(<*>)什么,可能会有助于了解它的基本含义。

那么到底是怎么回事Applicative,为什么我们要这样称呼呢?

什么Applicative在实践中达是解除的方式任意功能集成到一个Functor。考虑Maybe(可以说是最简单的非平凡的Functor)和Bool(同样是最简单的非平凡的数据类型)的组合。

maybeNot :: Maybe Bool -> Maybe Bool
maybeNot = fmap not

该功能fmap使我们可以not从进行中Bool升级Maybe Bool。但是,如果我们想举起(&&)呢?

maybeAnd' :: Maybe Bool -> Maybe (Bool -> Bool)
maybeAnd' = fmap (&&)

好吧,那根本不是我们想要!实际上,这几乎没有用。我们可以试着聪明和潜入另一BoolMaybe通过背...

maybeAnd'' :: Maybe Bool -> Bool -> Maybe Bool
maybeAnd'' x y = fmap ($ y) (fmap (&&) x)

...但是那不好。一方面,这是错误的。另一方面,它很丑。我们可以继续尝试,但是事实证明,没有办法提升多个参数的功能来处理任意参数Functor。烦人!

另一方面,如果使用MaybeMonad实例,我们可以轻松实现:

maybeAnd :: Maybe Bool -> Maybe Bool -> Maybe Bool
maybeAnd x y = do x' <- x
                  y' <- y
                  return (x' && y')

现在,仅翻译一个简单的函数Control.Monad就很麻烦-这就是为什么提供自动执行该功能的原因liftM2。名称中的2指的是它对正好两个参数的函数起作用;3、4和5参数函数也存在类似的功能。这些函数更好,但不是完美的,并且指定参数的数量很难看又笨拙。

这使我们进入介绍Applicative类型类的论文。在其中,作者基本上提出了两个观察结果:

  • 将多参数函数提升为a Functor是很自然的事情
  • 这样做并不需要具备 Monad

正常函数应用程序是通过简单的并置术语编写的,因此,为了使“提升的应用程序”尽可能简单自然,本文引入了infix运算符来代表应用程序,并提升为Functor,并提供了一个类型类来提供所需的内容。

所有这些将我们带到以下几点:(<*>)简单地表示函数应用程序-那么,为什么在发音上与在空白处“并置运算符”不同?

但是,如果这还不是很令人满意,我们可以观察到该Control.Monad模块还提供了对monad执行相同操作的函数:

ap :: (Monad m) => m (a -> b) -> m a -> m b

ap当然,“应用”的缩写在哪里。由于any Monad可以是Applicative并且ap仅需要后者中存在的功能的子集,我们也许可以说,如果(<*>)不是运算符,则应将其称为ap


我们还可以从另一个方向着手。在Functor提升操作被称为fmap,因为它是一个泛化map的列表操作。列表上什么样的功能会起作用(<*>)ap当然,列表上有什么功能,但这本身并不是特别有用。

实际上,列表可能有一种更自然的解释。当您查看以下类型签名时,会想到什么?

listApply :: [a -> b] -> [a] -> [b]

将列表并行排列,将第一个函数中的每个函数应用于第二个函数中的相应元素,这一想法很吸引人。不幸的是,对于我们的老朋友Monad,如果列表长度不同,此简单操作将违反monad法则。但这很好Applicative,在这种情况下,它(<*>)成为将广义版本组合在一起的一种方式,所以我们可以想象调用它吗?zipWithfzipWith


这个拉链的想法实际上带给我们了一个完整的圈子。还记得以前关于算式函子的数学知识吗?顾名思义,这是组合类半体和函子的结构的一种方法,它们都是熟悉的Haskell类型类:

class Functor f where
    fmap :: (a -> b) -> f a -> f b

class Monoid a where
    mempty :: a
    mappend :: a -> a -> a

如果将它们放在一个盒子中并摇晃一下,它们会是什么样?从此Functor我们将使结构的思想独立于其类型参数,并从其Monoid将函数的整体形式保留下来:

class (Functor f) => MonoidalFunctor f where
    mfEmpty :: f ?
    mfAppend :: f ? -> f ? -> f ?

我们不想假设有一种创建真正的“空”的方法Functor,并且我们不能想出任意类型的值,因此我们将修复mfEmptyas 的类型f ()

我们也不想强迫mfAppend需要一个一致的类型参数,所以现在我们有了这个:

class (Functor f) => MonoidalFunctor f where
    mfEmpty :: f ()
    mfAppend :: f a -> f b -> f ?

结果类型是mfAppend什么?我们有两种任意类型,我们一无所知,因此我们没有太多选择。最明智的做法是同时保留两者:

class (Functor f) => MonoidalFunctor f where
    mfEmpty :: f ()
    mfAppend :: f a -> f b -> f (a, b)

在这一点mfAppend现在是明确的一般化版本zip的列表,我们可以重建Applicative轻松:

mfPure x = fmap (\() -> x) mfEmpty
mfApply f x = fmap (\(f, x) -> f x) (mfAppend f x)

这也向我们显示了pure与a的identity元素相关的信息Monoid,因此它的其他好名称可能是暗示单位值,空操作等的任何名称。


这很长,因此总结一下:

  • (<*>) 只是一个经过修改的功能应用程序,因此您可以将其读取为“ ap”或“ apply”,也可以像正常功能应用程序一样完全删除它。
  • (<*>)也大致概括zipWith了列表,因此您可以将其读为“ zip函子与”,类似于阅读fmap为“映射函子与”。

第一个更接近Applicative类型类的意图-顾名思义,这就是我的建议。

实际上,我鼓励所有解除的应用程序操作员自由使用和不发音

  • (<$>),将单参数函数提升为 Functor
  • (<*>),该链接通过 Applicative
  • (=<<),它会将输入a的函数绑定Monad到现有计算中

从本质上讲,这三者只是常规功能的应用,而略微增加了一点。


6
@科林·科克伦(Colin Cochrane):您确定没有误拼写“长篇大论”吗?:)但是,我接受!我一直感觉到Applicative它所推广的功能性惯用风格并没有得到足够的爱,因此我无法抗拒借口颂扬其美德作为解释我(不)发音的一种方式(<*>)
CA McCann

+1!请随时进行类似的长篇大论stackoverflow.com/questions/2104446/...
格雷格·培根

6
Haskell是否可以使用的语法糖Applicative!有点像[| f a b c d |](如原论文所建议)。那么我们就不需要<*>组合器,您可以将这样的表达式称为“在函数上下文中的函数应用程序”的示例
Tom Crockett

1
@FredOverflow:不,我是说Monad。要么FunctorMonoid或其他任何东西,有一个涉及少于三个形容词一套行之有效的任期。“可应用的”只是一个毫无启发性的名称,尽管描述性很强,但它贴在一些需要的名称上。
CA McCann

1
@pelotom:请参阅[ stackoverflow.com/questions/12014524/…在那儿,好心的人向我展示了两种获取近似表示法的方法。
AndrewC 2012年

21

由于我没有改善CA McCann的技术答案的抱负,因此我将解决更为蓬松的问题:

如果您可以将其重命名pure为对像我这样的朋克更友好的东西,您会怎么称呼它?

作为一种替代方案,尤其是因为对Monad名为“ return” 的版本不断地充满焦虑和背叛,我提出了另一个名称,该名称建议了它的功能,可以满足最需要的命令式程序员,而且功能最强大……希望,每个人都可以抱怨以下内容:inject

取一个值。将其“注入”到FunctorApplicativeMonad,或什么都有,你。我对“ inject” 投了赞成票,并且批准了此消息。


4
我通常倾向于“单位”或“举升”之类的东西,但是在Haskell中它们已经具有太多其他含义。inject是个好名字,可能比我的好。不过,作为一个小小的注释,“注入”用于(我认为)Smalltalk和Ruby是某种左折方法。不过,我从来不了解名字的选择...
CA McCann 2010年

3
这是一个非常古老的线程,但是我认为inject在Ruby&Smalltalk中使用它是因为它就像您在列表中的每个元素之间“注入”一个运算符一样。至少,这就是我一直认为的方式。
乔纳森·斯特林

1
为了再次拿起老边线程:你不是注射运营商,你要替换(消除)是已经存在的构造。(反过来看,您正在旧数据注入新类型。)对于列表,消除是foldr。(您更换(:)[],其中(:)需要2个指定参数和[]是一个常数,因此foldr (+) 0 (1:2:3:[])1+2+3+0。)在Bool这只是if- - thenelse两个常量,选一个),以及Maybe它被称为maybe ... Haskell有这个没有单一的名称/功能,都有着不同的类型(一般而言,elim只是递归/归纳)
没有人

@CAMcCann Smalltalk是从Arlo Guthrie的一首歌中得来这个名字的,这首歌是关于越南战争的选秀的,其中收集了不幸的年轻人,挑选出来,有时拒绝他们,或者以其他方式注入。
Tom Anderson

7

简单来说:

  • <*>您可以称其为apply。所以,Maybe f <*> Maybe a可以读作申请Maybe fMaybe a

  • 您可以重命名pureof,就像许多JavaScript库一样。在JS,你可以创建一个MaybeMaybe.of(a)

此外,Haskell的Wiki在此处提供有关语言操作员发音的页面


3
(<*>) -- Tie Fighter
(*>)  -- Right Tie
(<*)  -- Left Tie
pure  -- also called "return"

来源:Chris Allen和Julie Moronuki撰写的《第一原理的Haskell编程》


据我所知,这些名字并没有完全流行。
dfeuer '16

@dfeuer等待使用该书作为主要学习材料的下一代Haskeller。
dmvianna '16

1
可能会发生。但是,这些名称很糟糕,因为它们与含义没有任何关系。
dfeuer '16

1
@dfeuer,我在任何地方都找不到好的解决方案。“ ap” /“ apply”与“ tie fighter”一样模糊。一切都是功能应用。但是,一个突如其来的名字可以通过使用获得含义。“苹果”就是一个很好的例子。顺便说一句,莫纳德的回报纯应用性的。这里没有发明。
dmvianna '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.