Types of Functors
函数式编程中有很多functors类型,我们可以使用Scala编程语言对他们进行描述。
- covariant functors —— 定义了map或fmap操作。
// covariant functor
trait Functor[F[_]] {
def fmap[A, B](f: A => B): F[A] => F[B]
}
- contravariant functors —— 定义了contramap操作。
// contravariant functor
trait Contravariant[F[_]] {
def contramap[A, B](f: B => A): F[A] => F[B]
}
- exponential functors —— 定义了xmap操作,也被称为invariant functors。
// exponential functor
trait Exponential[F[_]] {
def xmap[A, B](f: (A => B, B => A)): F[A] => F[B]
}
- applicative functor[^1] —— 定义了apply或<*>操作。
// applicative functor (abbreviated)
trait Applicative[F[_]] {
def apply[A, B](f: F[A => B]): F[A] => F[B]
}
- monad[^2] —— 定义了bind,flatMap或=<<操作。
// monad (abbreviated)
trait Monad[F[_]] {
def flatMap[A, B](f: A => F[B]): F[A] => F[B]
}
- comonad[^3] —— 定义了extend,coflatMap或<<=操作。
// comonad (abbreviated)
trait Comonad[F[_]] {
def coflatMap[A, B](f: F[A] => B): F[A] => F[B]
}
Remembering the different types
有时我会被问到怎么记住这些,以及它们的使用场景。答案有很多,但是所有这些functor类型都有一个共同的特征:
They all take an argument that is some arrangement of three type variables and then return a function with the type F[A] => F[B].
我通过一个表格去记忆这些参数排列(argument arrangements)的类型,以便帮我决定哪个抽象(abstraction)是合适的。当然,我也使用其它的方法,但是这个小技巧(particular technique)非常优雅和短小。如下所示:
functor | argument arrangement |
---|---|
covariant | A => B |
contravariant | B => A |
exponential | (A => B, B => A) |
applicative | F[A => B] |
monad | A => F[B] |
comonad | F[A] => B |
从这张表中我们可以看出,我们没有更多的理由去强调其中一个而忽略其他。例如,monads获得了很多关注以及指责,但是这是不应该的,在更大的背景下,这是相当无聊的。它只不过是它的参数(A => F[B])的一个处理。
无论如何,这个表是一个很好的方法来检查不同类型的抽象以及它们可能如何应用。 也有从别人那里得到一些的方法,但这是另外一回事了。 这就是全部,希望它有所帮助!
- applicative functors也定义了一个identity操作,(def insert[A]: A => F[A]),然而,它省略了。
- monads也定义了一个identity操作,(def insert[A]: A => F[A]),然而,它省略了。
- comonads也定义了一个identity操作, (def extract[A]: F[A] => A),然而,它省略了。