![](/img/trans.png)
[英]Functor is for (a -> b) -> (f a -> f b), what is for (Category c) => c a b -> c (f a) (f b)?
[英]what does (<*>) :: f (a -> b) -> f a -> f b exactly do in the Functor class
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
据我了解,它采用一个函数f,其中另一个函数(a -> b)
作为其参数返回一个函数f
。 将f
应用于a
然后返回函数f
并将f
应用于b
。
这是一个例子:
Prelude> (+) <$> Just 2 <*> Just 3
Just 5
但是我不太了解它是如何工作的。
我猜(+)
应该是f
, Just 2
和Just 3
应该分别是a
和b
。 那么(a -> b)
什么?
据我了解,它需要一个函数来...
不幸的是,这是不正确的。 在这种情况下, f
是类型,而不是函数。 具体地说, f
是类型为* -> *
的“高级类型”。 类型f
是函子。
在这种情况下, f
是Maybe
。 因此,我们可以重写函数类型,使其专门用于Maybe
:
pure :: a -> Maybe a
(<*>) :: Maybe (a -> b) -> Maybe a -> Maybe b
到此为止,它将变得更加清晰。 对于pure
,有两种不同的可能定义,但是只有一种才有意义:
pure = Just
运算符x <$> y
与pure x <*> y
,因此如果您写出:
(+) <$> Just 2 <*> Just 3
然后我们可以将其重写为:
pure (+) <*> pure 2 <*> pure 3
尽管从技术上讲,这是更通用的类型。 使用函子定律,我们知道pure x <*> pure y
与pure (xy)
相同,因此我们得到
pure ((+) 2) <*> pure 3
pure ((+) 2 3)
pure (2 + 3)
在这种情况下,我们a
和b
是类型,但是由于<*>
出现两次,因此它们实际上在每种情况下都有不同的类型。
在第一个<*>
, a
为Int
, b
为Int -> Int
。 在第二个<*>
, a
和b
均为Int
。 (从技术上讲,您获得的是Int
通用版本,但这对问题并不是很重要。)
应用函子作为应用样式编程“成语”引入Haskell。 解开这个短语,我们有“应用样式编程”; 这只是函数对参数的应用。 我们也有“成语”或具有特殊含义的语言短语。 例如,“给猫和狗下雨”是下大雨的习语。 应用函子放在一起,是具有特殊含义的函数应用程序。
例如,在Dietrich Epp的带领下,一个函数定义了一个anApplication
,
anApplication = f a
where
f = (+2)
a = 3
和anIdiomaticApplication
,通过惯用应用程序定义,
anIdiomaticApplication = f <*> a
where
f = Just (+2)
a = Just 3
这些定义的顶层结构相似。 区别? 第一个具有空格-正常功能应用程序-第二个具有<*>
惯用功能应用程序。 这说明<*>
如何促进应用风格:只需使用<*>
代替空格。
应用程序<*>
是惯用的,因为它具有除纯函数应用程序以外的含义。 通过说明的方式,在一个anIdiomaticApplication
我们有这样的东西:
f <*> a :: Maybe (Int -> Int) <*> Maybe Int
在此,类型中的<*>
用于表示与真实<*>
签名相对应的类型级别函数*。 对于类型<*>
我们将f
和a
(分别为Maybe (Int -> Int)
和Maybe Int
)应用类型参数。 申请后,我们有
f <*> a :: Maybe Int
作为中间步骤,我们可以想像
f <*> a :: Maybe ((Int -> Int) _ Int)
_
是常规功能应用程序的类型级别替身。
在这一点上,我们终于可以看到习惯用语了。 在Maybe
上下文/习惯用法中, f <*> a
类似于常规函数应用程序(Int -> Int) _ Int
。 因此, <*>
只是在特定上下文中发生的函数应用程序。
在分开时,我将强调理解<*>
仅部分理解其用法。 我们可以理解, f <*> a
只是函数应用程序,具有一些特殊的含义。 根据适用法律,我们还可以假定惯用的应用会在某种程度上是明智的。
但是,如果您查看<*>
并感到困惑,因为那里的内容很少,请不要感到惊讶。 我们还必须精通各种Haskell习语。 例如,在Maybe
惯用语中,函数或值都可能不存在,在这种情况下,输出将为Nothing
。 当然,还有很多其他人,但是只要熟悉Either a
和State s
,就应该为各种不同的模型建模。
*像这样的事情实际上可以由封闭型家庭(未经测试)完成
type family IdmApp f a where
IdmApp (f (a->b)) a = f b
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.