when map over a function 当你有 andThen 时很有用

When map over a function is useful when you have andThen

使用 Scalaz,一个函数可以映射到另一个函数上。我什么时候想使用 map 而不是 andThen?使用 map 有明显的优势吗?谢谢

例如,

val f: Int => Int = (a) => a + 10

val g: Int => Int = (a) => a * 100

(f map g map {_*3})(10) == (f andThen g andThen {_*3})(10)  // true

暂时搁置实现细节,map andThen函数(在A => ?的仿函数实例下),以及如果我们专门讨论功能而不是更高层次的抽象,那么谈论偏爱一个而不是另一个真的没有多大意义。

map 这样的方法(以及类型 类 像 Functor 更普遍)允许我们做的是对特定类型或类型构造函数的抽象。例如,假设我们要编写一个适用于 A => IntKleisli[Option, A, Int]incrementResult 方法。这些类型在继承方面没有任何共同点(缺少 AnyRef,这是无用的),但是 A => ?Kleisli[Option, A, ?] 都是函子,所以我们可以这样写:

import scalaz._, Scalaz._

def incrementResult[F[_]: Functor](f: F[Int]): F[Int] = f.map(_ + 1)

然后像这样使用它(注意我使用 kind-projector 来稍微简化类型语法):

scala> val plainOldFuncTriple: Int => Int = _ * 3
plainOldFuncTriple: Int => Int = <function1>

scala> val optionKleisliTriple: Kleisli[Option, Int, Int] = Kleisli(i => Some(i * 3))
optionKleisliTriple: scalaz.Kleisli[Option,Int,Int] = Kleisli(<function1>)

scala> val f = incrementResult[Int => ?](plainOldFuncTriple)
f: Int => Int = <function1>

scala> val k = incrementResult[Kleisli[Option, Int, ?]](optionKleisliTriple)
k: scalaz.Kleisli[Option,Int,Int] = Kleisli(<function1>)

scala> f(10)
res0: Int = 31

scala> k(10)
res1: Option[Int] = Some(31)

在这种情况下,具体来说,有更好的方法来实现这个操作,但它显示了一般的想法——我们无法使用 andThen 编写一个既适用于普通函数又适用于 Kleisli 箭头的方法,但是我们可以使用 map 给我们的额外抽象级别。

所以回答你的问题——如果你想抽象所有具有仿函数实例的类型构造函数,你会使用 map,但如果你专门使用函数,map andThen,并且——只要我们仍然搁置实现细节——你选择哪个并不重要。


脚注:Scalaz 的 syntax 包为具有仿函数实例的类型的值提供的 map 是作为扩展方法实现的,因此有一点点开销(都在编译时)和运行时)涉及在函数上使用 map 而不是 andThen。如果您只使用函数而不需要额外的抽象,那么,您不妨使用 andThen.