Functor 有什么用?

How are Functors useful?

我们知道任何泛型类型 F[_] withmap 方法,符合某些 laws,是一个 函子 。例如,List[_]Option[_]F[A] = Env => A 是函子。我只是想知道这个函子抽象是否有意义。

我如何利用它们是仿函数这一事实?您能否展示一个使用 map 并且实际有用的非平凡计算示例?

好吧,一旦你知道某个东西是 Functor,你不仅会得到 map,你还会得到所有你可以用它派生的函数

例如,可以以适用于任何仿函数的方式派生函数 lift

Lift 将 "lift" 函数从 A => BF[A] => F[B] 对于某些 Functor F[_] 并定义为

def lift[A, B](f: A => B): F[A] => F[B] = map(_)(f)

如果您使用的库 cats or scalaz then you get these functions for free. The cats documentation 还有一些您可能感兴趣的其他示例

函数等概念的最大好处之一是,泛型结构允许您从更简单的仿函数构建更复杂的类型,并保证这些复杂类型具有某些属性。可以理解,当您像您所做的那样孤立地考虑函子时,函子似乎毫无意义,但是您学习和掌握的此类构造越多,它们就会变得越来越有用。

一个更简单的例子是,几种组合函子的方法也产生了一个函子;例如,如果 List[A]Option[A] 是函子,那么:

  • 函子的组成: List[Option[A]]Option[List[A]]
  • 函子的乘积: (List[A], Option[A])
  • 函子的总和: Either[List[A], Option[A]]

我的知识不足以用 Scala 写出来,但在 Haskell 中,这些事实可以转化为通用代码,例如这些示例:

-- A generic type to represent the composition of any two functors
-- `f` and `g`.
newtype Compose f g a = Compose { getCompose :: f (g a) }

-- If `f` and `g` are functors, so is `Compose f g`.
instance (Functor f, Functor g) => Functor (Compose f g) where
  fmap f (Compose fga) = Compose (fmap (fmap f) fga)

这是一个非常简单的例子,但是:

  • 它至少作为 分析工具 已经很有用了。人们在实践中编写的 lot 数据类型,当你从这个例子的角度来看它们时,结果是更简单的函子的乘积、总和或组合。所以一旦你理解了这些结构你就可以在你写一个复杂类型时自动 "sense" 它是一个函子,以及如何写它的 map() 操作。
  • 更详细的示例具有相同的风格:
    • 我们有一个通用构造,它在使用实现Functor;
    • 的类型实例化时保证某些契约
    • 当我们向任何类型添加 Functor 实现时,我们就能够在该构造中使用该类型。

一个更详细的例子是 free monads(link 有一个扩展的 Scala 例子),一个依赖于用户提供的 Functors 来定义 "instructions" 的语言。其他 link(这些大多直接来自 Google 搜索):

我不懂 Scala,但在 Haskell 中,Functor class 对定义 Van Laarhoven-style lenses:

至关重要
type Lens' s a = forall f . Functor f => (a -> f a) -> s -> f s

这些透镜通常是为特定相关类型 sa 定义的,但它们与任意函子一起使用对于它们的实用性至关重要。

Functor 作为 ApplicativeTraversable 的超级 class 的作用也很重要。在使用这些更强大的抽象时,使用 fmap 方法通常非常有用。