函子的目的

The purpose of functors

我正在尝试理解仿函数并且理解其概念但不理解其目的?

考虑以下示例:

val list1 = List(1,2,3)
val list2 = Functor[List].map(list1)(_ * 2)

好处是什么:

list1.map(x => x * 2)

?

目的不一定是Functor[List].map(list1)(_ * 2)而是:

def timesTwo[F[_]: Functor](f: F[Int]) = 
  Functor[F].map(f)(_ * 2)

对可以映射的一切进行抽象的能力。

仿函数是一种类型 class,它抽象了所有可以进行的类似映射操作的类型。这样我们就可以统一操作这些类型的实例了。

我认为看一下仿函数的 map 函数的类型签名很有用

map :: (a -> b) -> Functor a -> Functor b

这为我们提供了一种将值放入容器 (Functor) 并使用普通函数(使用 map)对该值进行操作的方法,所有这些都无需从容器中取出值。

然后可以将 Functor 视为高阶类型;也就是说,它是一个包含另一个值的值,但是有一个统一的接口来与之交互——这个接口给了函子一种独特的表达形式,使它们特别适合某些问题

仿函数是类型构造函数F[_]和函数

def fmap[A,B](f: A => B): F[A] => F[B]

(这与 cats 中的写法不同,但它实现相同并且可以互换)

那么这是什么意思呢? 类型构造函数基本上是类型之间的映射你给它一个类型 A,它给你一个结果类型 F[A].

您拥有函数 fmap 的事实意味着以下内容:每次您能够从 A 转到 F[A] 时,您可以从 F[A] 转到 F[B] B.

法律

每个函子都必须遵守这些恒等式

  1. fmap(identity[A]) == identity[F[A]]
  2. fmap(a compose b) == fmap(a) compose fmap (b)

函子法则确保类型级函数(类型构造函数)和值级函数(A => BF[A] => F[B])可以很好地协同工作。

有什么好处

好处是而不是您可以使用不同的语法编写一些函数。事实上,在你的例子中 Functor[List].map(list1)(_ * 2)list1.map(_ * 2).

更难写

好处是您可以编写适用于任何仿函数的函数。

这是一个例子

import cats.Functor

def foo[A,B,F[_]: Functor](fb: F[B], ab: A => B)(eab: Either[F[A],F[B]]): F[B] = 
    eab.fold(fa => Functor[F].map(fa)(ab),identity)