什么是< *>被称为,它是做什么的? [英] What is <*> called and what does it do?

查看:189
本文介绍了什么是< *>被称为,它是做什么的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Applicative类型类中的这些功能如何工作?

How do these functions in the Applicative typeclass work?

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

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

(That is, if they weren't operators, what might they be called?)

请注意,如果您可以将pure重命名为对非数学家更友好的名称,您会怎么称呼它?

As a side note, if you could rename pure to something more friendly to non-mathematicians, what would you call it?

推荐答案

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

Sorry, I don't really know my math, so I'm curious how to pronounce the functions in the Applicative typeclass

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

Knowing your math, or not, is largely irrelevant here, I think. As you're probably aware, Haskell borrows a few bits of terminology from various fields of abstract math, most notably Category Theory, from whence we get functors and monads. The use of these terms in Haskell diverges somewhat from the formal mathematical definitions, but they're usually close enough to be good descriptive terms anyway.

Applicative类型类位于FunctorMonad之间,因此人们希望它具有相似的数学基础. Control.Applicative模块的文档始于:

The Applicative type class sits somewhere between Functor and Monad, so one would expect it to have a similar mathematical basis. The documentation for the Control.Applicative module begins with:

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

This module describes a structure intermediate between a functor and a monad: it provides pure expressions and sequencing, but no binding. (Technically, a strong lax monoidal functor.)

嗯.

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

我想不像Monad那样吸引人.

这基本上可以归结为Applicative并不对应于任何在数学上特别有趣的概念,因此没有现成的术语可以捕捉到它在其中使用的方式.哈斯克尔.因此,暂时搁置数学.

What all this basically boils down to is that Applicative doesn't correspond to any concept that's particularly interesting mathematically, so there's no ready-made terms lying around that capture the way it's used in Haskell. So, set the math aside for now.

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

If we want to know what to call (<*>) it might help to know what it basically means.

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

So what's up with Applicative, anyway, and why do we call it that?

Applicative实际上是一种将任意函数提升为Functor的方法.考虑Maybe(可能是最简单的非平凡的Functor)和Bool(同样是最简单的非平凡的数据类型)的组合.

What Applicative amounts to in practice is a way to lift arbitrary functions into a Functor. Consider the combination of Maybe (arguably the simplest non-trivial Functor) and Bool (likewise the simplest non-trivial data type).

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

功能fmap使我们可以将not从使用Bool的工作提升到使用Maybe Bool的工作.但是,如果我们想提起(&&)怎么办?

The function fmap lets us lift not from working on Bool to working on Maybe Bool. But what if we want to lift (&&)?

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

好吧,这根本不是我们想要的 !实际上,这几乎没有用.我们可以尝试变得聪明,并通过背面将另一个Bool潜入Maybe ...

Well, that's not what we want at all! In fact, it's pretty much useless. We can try to be clever and sneak another Bool into Maybe through the back...

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

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

...but that's no good. For one thing, it's wrong. For another thing, it's ugly. We could keep trying, but it turns out that there's no way to lift a function of multiple arguments to work on an arbitrary Functor. Annoying!

另一方面,如果使用MaybeMonad实例,我们可以轻松做到这一点:

On the other hand, we could do it easily if we used Maybe's Monad instance:

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参数函数也存在类似的功能.这些功能更好,但并不完美,并且指定参数的数量非常丑陋和笨拙.

Now, that's a lot of hassle just to translate a simple function--which is why Control.Monad provides a function to do it automatically, liftM2. The 2 in its name refers to the fact that it works on functions of exactly two arguments; similar functions exist for 3, 4, and 5 argument functions. These functions are better, but not perfect, and specifying the number of arguments is ugly and clumsy.

这将我们带到了介绍了Applicative类型类的文件.在其中,作者基本上提出了两个观察结果:

Which brings us to the paper that introduced the Applicative type class. In it, the authors make essentially two observations:

  • 将多参数函数提升为Functor是很自然的事情
  • 这样做并不需要Monad
  • 的全部功能
  • Lifting multi-argument functions into a Functor is a very natural thing to do
  • Doing so doesn't require the full capabilities of a Monad

普通函数应用程序是用术语的简单并置编写的,因此,为了使提升的应用程序"尽可能简单自然,本文引入了中缀运算符来代表应用程序,并将其提升到Functor ,以及一个类型类,以提供所需的内容.

Normal function application is written by simple juxtaposition of terms, so to make "lifted application" as simple and natural as possible, the paper introduces infix operators to stand in for application, lifted into the Functor, and a type class to provide what's needed for that.

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

All of which brings us to the following point: (<*>) simply represents function application--so why pronounce it any differently than you do the whitespace "juxtaposition operator"?

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

But if that's not very satisfying, we can observe that the Control.Monad module also provides a function that does the same thing for monads:

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

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

Where ap is, of course, short for "apply". Since any Monad can be Applicative, and ap needs only the subset of features present in the latter, we can perhaps say that if (<*>) weren't an operator, it should be called ap.

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

We can also approach things from the other direction. The Functor lifting operation is called fmap because it's a generalization of the map operation on lists. What sort of function on lists would work like (<*>)? There's what ap does on lists, of course, but that's not particularly useful on its own.

事实上,对于列表而言,也许有一种更自然的解释.当您查看以下类型签名时会想到什么?

In fact, there's a perhaps more natural interpretation for lists. What comes to mind when you look at the following type signature?

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

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

There's something just so tempting about the idea of lining the lists up in parallel, applying each function in the first to the corresponding element of the second. Unfortunately for our old friend Monad, this simple operation violates the monad laws if the lists are of different lengths. But it makes a fine Applicative, in which case (<*>) becomes a way of stringing together a generalized version of zipWith, so perhaps we can imagine calling it fzipWith?

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

This zipping idea actually brings us full circle. Recall that math stuff earlier, about monoidal functors? As the name suggests, these are a way of combining the structure of monoids and functors, both of which are familiar Haskell type classes:

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

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

如果将它们放在一个盒子中并摇晃一下,它们会是什么样子?从Functor开始,我们将保持结构与其类型参数无关的想法,从Monoid开始,我们将保持函数的整体形式:

What would these look like if you put them in a box together and shook it up a bit? From Functor we'll keep the idea of a structure independent of its type parameter, and from Monoid we'll keep the overall form of the functions:

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

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

We don't want to assume that there's a way to create an truly "empty" Functor, and we can't conjure up a value of an arbitrary type, so we'll fix the type of mfEmpty as f ().

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

We also don't want to force mfAppend to need a consistent type parameter, so now we have this:

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

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

What's the result type for mfAppend? We have two arbitrary types we know nothing about, so we don't have many options. The most sensible thing is to just keep both:

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

此时mfAppend现在显然是列表中zip的广义版本,我们可以轻松地重建Applicative:

At which point mfAppend is now clearly a generalized version of zip on lists, and we can reconstruct Applicative easily:

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

这也向我们表明pureMonoid的标识元素有关,因此其他好名字可能是暗示单位值,空操作等的任何名称.

This also shows us that pure is related to the identity element of a Monoid, so other good names for it might be anything suggesting a unit value, a null operation, or such.

那很长,所以总结一下:

That was lengthy, so to summarize:

  • (<*>)只是一个经过修改的功能应用程序,因此您可以将其读取为"ap"或"apply",也可以像正常功能应用程序一样完全删除它.
  • (<*>)还大致概括了列表中的zipWith,因此您可以将其阅读为带有zip函子",类似于将fmap阅读为使用...映射函子".
  • (<*>) is just a modified function application, so you can either read it as "ap" or "apply", or elide it entirely the way you would normal function application.
  • (<*>) also roughly generalizes zipWith on lists, so you can read it as "zip functors with", similarly to reading fmap as "map a functor with".

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

The first is closer to the intent of the Applicative type class--as the name suggests--so that's what I recommend.

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

In fact, I encourage liberal use, and non-pronunciation, of all lifted application operators:

  • (<$>),它将单参数函数提升为Functor
  • (<*>),通过Applicative
  • 链接多参数函数
  • (=<<),它将输入Monad的函数绑定到现有计算中
  • (<$>), which lifts a single-argument function into a Functor
  • (<*>), which chains a multi-argument function through an Applicative
  • (=<<), which binds a function that enters a Monad onto an existing computation

从本质上讲,这三个函数只是常规的函数应用程序,而只是稍微加了一点.

All three are, at heart, just regular function application, spiced up a little bit.

这篇关于什么是&lt; *&gt;被称为,它是做什么的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆