Closed. This question is opinion-based。它当前不接受答案。












想改善这个问题吗?更新问题,以便editing this post用事实和引用来回答。

2年前关闭。



Improve this question




您如何在Applicative类型类中发音这些函数:
(<*>) :: f (a -> b) -> f a -> f b
(*>)  :: f a -> f b -> f b
(<*)  :: f a -> f b -> f a

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

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

最佳答案

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

我认为,是否了解您的数学与这里无关。您可能已经知道,Haskell从抽象数学的各个领域借用了一些术语,最著名的是Category Theory,从中我们得到了函子和单子(monad)。在Haskell中,这些术语的使用与正式的数学定义有所不同,但它们通常足够接近,无论如何都是好的描述性术语。
Applicative类型类位于FunctorMonad之间,因此人们希望它具有相似的数学基础。 Control.Applicative模块的文档开始于:

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


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 (&&)

好吧,那根本不是我们想要的!实际上,这几乎没有用。我们可以尝试变得聪明,并通过背面将另一个Bool潜入Maybe中...
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参数函数也存在类似的功能。这些函数是更好的,但不是完美的,并且指定参数的数量是丑陋且笨拙的。

这将我们带到paper that introduced the Applicative type class。在其中,作者基本上提出了两个观察:
  • 将多参数函数提升为Functor是很自然的事情
  • 这样做不需要Monad的全部功能

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

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

    但是,如果这还不能令人满意,我们可以观察到Control.Monad模块还提供了对monad执行相同操作的函数:
    ap :: (Monad m) => m (a -> b) -> m a -> m b
    

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

    我们也可以从另一个方向着手。 Functor提升操作称为fmap,因为它是列表上map操作的概括。列表上的哪种功能可以像(<*>)一样工作?当然,ap在列表上做了什么,但是它本身并不是特别有用。

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

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

    这个压缩的想法实际上使我们充满了圈子。还记得以前关于单曲面函子的数学知识吗?顾名思义,这是组合类半体和函子的结构的一种方法,它们都是熟悉的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,并且我们不能想出一个任意类型的值,因此我们将mfEmpty的类型固定为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)
    

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

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

  • 第一个更接近Applicative类型类的意图-顾名思义-因此,我建议这样做。

    实际上,我鼓励所有解除的应用程序操作员自由使用并禁止其发音:
  • (<$>),它将单参数函数提升为Functor
  • (<*>),它通过Applicative链接多参数函数
  • (=<<),它将将Monad输入的函数绑定(bind)到现有的计算

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

    关于haskell - Haskell:<*>的发音是什么? ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30799228/

    10-13 03:09