(<*>):: f(a-> b)-> f a-> f b在Functor类中到底做了什么

时间:2018-08-10 01:12:30

标签: haskell functor applicative

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

但是我不太了解它是如何工作的。

我猜(+)应该是fJust 2Just 3应该分别是ab。那么(a -> b)是什么?

2 个答案:

答案 0 :(得分:7)

  

据我了解,它需要一个函数f ...

不幸的是,这是不正确的。在这种情况下,f是类型,而不是函数。具体来说,f是类型为* -> *的“高级类型”。类型f是函子。

在这种情况下,fMaybe。因此,我们可以重写函数类型,使其专门用于Maybe

pure :: a -> Maybe a
(<*>) :: Maybe (a -> b) -> Maybe a -> Maybe b

到此为止,它会变得更加清晰。 pure可能有两种不同的定义,但只有一种才有意义:

pure = Just

运算符x <$> ypure x <*> y相同,因此如果您写出:

(+) <$> Just 2 <*> Just 3

然后我们可以将其重写为:

pure (+) <*> pure 2 <*> pure 3

尽管从技术上讲,它具有更通用的类型。使用函子定律,我们知道pure x <*> pure ypure (x y)相同,所以我们得到

pure ((+) 2) <*> pure 3
pure ((+) 2 3)
pure (2 + 3)

在这种情况下,我们的ab类型,但是由于<*>出现两次,因此它们在每种情况下实际上都有不同的类型。

在第一个<*>中,aInt,而bInt -> Int。 在第二个<*>中,ab均为Int。 (从技术上讲,您可以获得Int的通用版本,但这对问题并不重要。)

答案 1 :(得分:1)

应用函子是作为应用样式编程"Idioms" 引入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(分别为aMaybe (Int -> Int))的类型实参应用于类型Maybe Int。申请后我们有

 f <*> a :: Maybe Int

作为中间步骤,我们可以想像

 f <*> a :: Maybe ((Int -> Int) _ Int)

其中_是常规功能应用程序的类型级别替身。

在这一点上,我们终于可以看到习惯用法了。在f <*> a上下文/习惯用法中,(Int -> Int) _ Int就像普通功能应用程序Maybe。因此,<*>只是在特定上下文中发生的函数应用程序。

在分开时,我将强调理解<*>仅部分地了解其用法。我们可以理解,f <*> a只是函数应用程序,具有一些特殊的含义。根据适用法律,我们还可以假定惯用的应用在某种程度上是明智的。

但是,如果您看着<*>并感到困惑,因为那里的内容很少,请不要感到惊讶。我们还必须精通各种Haskell习语。例如,在Maybe惯用语中,可能不存在函数或值,在这种情况下,输出将为Nothing。当然,还有许多其他人,但是仅熟悉Either aState s应该可以对各种各样的不同种类进行建模。

*类似的事情实际上可以由封闭类型的家族(未经测试)

完成
type family IdmApp f a where
   IdmApp (f (a->b)) a = f b