Haskell:< *>发音? [英] Haskell: How is <*> pronounced?
问题描述
(< *>):: f(a)这些函数在Applicative类型类中如何发音? - > b) - > f a - > f b
(*>):: f a - > f b - > f b
(< *):: f a - > f b - > fa
(也就是说,如果他们不是运营商,他们会被称为什么?)
请注意,如果您可以将纯粹
重命名为对非数学家更友好的事物,您会怎样称呼它?
对不起,我不太了解我的数学,所以我很好奇在Applicative类型类中发音函数
在我看来,知道你的数学或许没有多大意义。正如你可能知道的那样,Haskell从抽象数学的各个领域借用了一些术语,特别是类别理论,从那里我们得到函子和单子。这些术语在Haskell中的用法与正式的数学定义有所分歧,但它们通常足够接近,无论如何都是很好的描述性术语。
Applicative
type类位于 Functor
和 Monad
之间的某处,所以人们可能会期望它有一个相似的数学基础。 Control.Applicative
模块的文档始于:
该模块描述了一个函子和monad之间的中间结构:它提供纯粹的表达式和排序,但没有约束力。 (技术上来说,这是一个强势松散monoidal函子。)
嗯。
class(Functor f)=> StrongLaxMonoidalFunctor f其中
。 。 。
与 Monad
不同,想想。
基本上归结为 Applicative
不符合任何概念,特别是<有趣的在数学上,所以没有现成的术语可以捕捉到它在Haskell中的使用方式。所以,现在就把数学放在一边。
如果我们想知道叫什么( <>)
它可能有助于了解它的基本含义。
所以 Applicative
,无论如何,为什么 do 我们称之为?
什么应用$实际上c $ c>是一种将任意函数提升为
Functor
的方法。考虑 Maybe
(可以说是最简单的不重要的 Functor
)和 Bool code>(同样是最简单的非平凡数据类型)。
maybeNot :: Maybe Bool - >也许Bool
maybeNot = fmap不是
函数 fmap
让我们从
Bool
的工作中解除不是来处理
Maybe Bool
。但是,如果我们要解除(&&)
?
maybeAnd':: Maybe Bool - > Maybe(Bool - > Bool)
maybeAnd'= fmap(&& amp;)
好吧,那不是我们想要的 !事实上,它几乎没用。我们可以尝试聪明地将另一个 Bool
放入 Maybe
后面......
maybeAnd'':: Maybe Bool - >布尔 - >也许Bool
maybeAnd''xy = fmap($ y)(fmap(&& x)x)
...但这并不好。首先,这是错误的。另一件事,它很丑陋。我们可以继续尝试,但事实证明,没有办法解决多个参数的函数来处理任意 Functor
。另一方面,如果我们使用 Maybe
的<$ c $,我们可以轻松地做到这一点c> Monad instance:
maybeAnd :: Maybe Bool - >也许Bool - >可能Bool
maybeAnd xy = do x'< - x
y'< - y
return(x'&& y')
现在,为了翻译一个简单的函数,这很麻烦 - 这就是为什么 Control.Monad
提供了一个自动执行的函数, liftM2
。名称中的2表示它在两个参数的函数上起作用的事实;对于3,4和5个参数函数存在类似的函数。这些函数更好,但并不完美,并且指定参数的数目是丑陋和笨拙的。
这将我们带入介绍Applicative type class的文章。其中,作者提出了两条观察: 正常功能应用程序是通过简单的术语并列编写的,因此为了使解除应用程序尽可能简单自然,本文引入了 infix运营商站在应用程序中,提升到 所有这些都让我们看到以下几点: 但是,如果这不是很令人满意,我们可以观察
Functor
是很自然的事情
Monad
的完整功能
Functor
和一个类型类,以提供所需的功能。
(< *>)
不同于你做空白的并列运算符?
Control。 Monad
模块也提供了一个相同的功能r monads:
ap ::(Monad m)=> m(a - > b) - > m a - > mb
当然, ap
适用的缩写。因为任何 Monad
都可以是 Applicative
,并且 ap
只需要在后者中存在的特征子集,我们可以说 if(code>(*))不是一个运算符,它应该被称为 ap
。
我们也可以从其他方向。 Functor
提升操作称为 fmap
,因为它是 map $ c的泛化$ c>列表中的操作。列表上的什么样的函数可以像
(<>)
一样工作?当然,列表中有 ap
,但这并不是特别有用。
事实上,列表可能有更自然的解释。当你看到下面的类型签名时想到什么?
listApply :: [a - > b] - > [a] - > [b]
并列列表的想法非常诱人,功能在第一个到相应的第二个元素。不幸的是,对于我们的老朋友 Monad
,如果列表长度不同,这个简单的操作违反了monad定律。但是,在 Applicative
将 zipWith
的广义版本串在一起,因此我们可以想象将它称为 fzipWith
?
这个压缩的想法实际上给我们带来了完整的圆圈。回想一下数学的东西,关于monoidal函数?顾名思义,这些方法就是将monoids和functor的结构相结合,两者都是熟悉的Haskell类型类:
> class Functor f wherefmap ::(a - > b) - > f a - > f b
class Monoid a where
mempty :: a
mappend :: a - > a - > a
如果您将它们放在一个盒子中并将它摇动一下,这些看起来会是什么样子?从 Functor
,我们将保持独立于其类型参数结构的概念,并从 Monoid
我们将保留函数的整体形式:
class(Functor f)=> MonoidalFunctor f其中
mfEmpty :: f?
mfAppend :: f? - > F ? - > F ?
我们不想假设有一种方法可以创建一个真正的空 Functor
,并且我们无法想出任意类型的值,所以我们将 f()
。
我们也不想强制 mfAppend
需要一个一致的类型参数,所以现在我们有这个:
$ p $ class(Functor f)=> MonoidalFunctor f其中
mfEmpty :: f()
mfAppend :: f a - > f b - > F ?
mfAppend
的结果类型是什么?我们有两种任意类型的任意类型,所以我们没有太多的选择。最明智的就是保持两者:
class(Functor f)=> MonoidalFunctor f其中
mfEmpty :: f()
mfAppend :: f a - > f b - > f(a,b)
zip
的通用版本,我们可以轻松地重建 Applicative
:
pre $
mfPure x = fmap(\() - > x)mfEmpty
mfApply fx = fmap(\(f,x ) - > fx)(mfAppend fx)
这也显示纯
与 Monoid
的标识元素相关,所以其他好的名称可能是任何暗示单位值,空操作或这样。
这段时间太长了,所以总结一下:
(*)
只是一个修改后的函数应用程序,所以您可以将其读为ap或apply ,或者完全按照您正常运行应用程序的方式将其删除。 zipWith
,所以你可以把它看作zip functors with,类似于阅读 fmap
作为映射仿函数。
第一个更接近应用类型类 - 顾名思义 - 这就是我的建议。
实际上,我鼓励自由使用,所有被解除的应用程序运营商的语音和非语音: ,在内心,只是普通的功能应用程序,加点点儿。 How do you pronounce these functions in the Applicative typeclass: (That is, if they weren't operators, what might they be called?) As a side note, if you could rename Sorry, I don't really know my math, so I'm curious how to pronounce the functions in the Applicative typeclass 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. The 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.) Hmm. Not quite as catchy as What all this basically boils down to is that If we want to know what to call So what's up with What The function 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 ...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 On the other hand, we could do it easily if we used Now, that's a lot of hassle just to translate a simple function--which is why Which brings us to the paper that introduced the Applicative type class. In it, the authors make essentially two observations: 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 All of which brings us to the following point: But if that's not very satisfying, we can observe that the Where We can also approach things from the other direction. The In fact, there's a perhaps more natural interpretation for lists. What comes to mind when you look at the following type signature? 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 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: What would these look like if you put them in a box together and shook it up a bit? From We don't want to assume that there's a way to create an truly "empty" We also don't want to force What's the result type for At which point This also shows us that That was lengthy, so to summarize: The first is closer to the intent of the In fact, I encourage liberal use, and non-pronunciation, of all lifted application operators: All three are, at heart, just regular function application, spiced up a little bit. 这篇关于Haskell:< *>发音?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
(< $>) ,它将单参数函数提升为
Functor
(< ; *>)
,它链接了一个多参数func通过 Applicative
(=<< /< c $ c>将一个输入
Monad
的函数绑定到一个已有的计算上
(<*>) :: f (a -> b) -> f a -> f b
(*>) :: f a -> f b -> f b
(<*) :: f a -> f b -> f a
pure
to something more friendly to non-mathematicians, what would you call it?
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:
class (Functor f) => StrongLaxMonoidalFunctor f where
. . .
Monad
, I think.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.
(<*>)
it might help to know what it basically means.Applicative
, anyway, and why do we call it that?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
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
into Maybe
through the back...maybeAnd'' :: Maybe Bool -> Bool -> Maybe Bool
maybeAnd'' x y = fmap ($ y) (fmap (&&) x)
Functor
. Annoying!Maybe
's Monad
instance:maybeAnd :: Maybe Bool -> Maybe Bool -> Maybe Bool
maybeAnd x y = do x' <- x
y' <- y
return (x' && y')
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.
Functor
is a very natural thing to doMonad
Functor
, and a type class to provide what's needed for that.(<*>)
simply represents function application--so why pronounce it any differently than you do the whitespace "juxtaposition operator"? 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
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
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.listApply :: [a -> b] -> [a] -> [b]
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
?
class Functor f where
fmap :: (a -> b) -> f a -> f b
class Monoid a where
mempty :: a
mappend :: a -> a -> a
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
, and we can't conjure up a value of an arbitrary type, so we'll fix the type of mfEmpty
as f ()
.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
? 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
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)
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.
(<*>)
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
type class--as the name suggests--so that's what I recommend.
(<$>)
, 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