当你拥有andThen时,在函数上映射很有用

时间:2016-07-02 09:42:44

标签: scala scalaz

使用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

1 个答案:

答案 0 :(得分:12)

暂时搁置实施细节,map andThen用于函数(在A => ?的函子实例下),并不是真的如果我们特别谈论的是函数而不是更高级别的抽象,那么谈论一个优先于另一个是很有意义的。

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

Kleisli[Option, A, ?]

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

import scalaz._, Scalaz._

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

在这种情况下,特别是有更好的方法来实现这个操作,但是它显示了一般的想法 - 我们不能使用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) 编写适用于普通函数和Kleisli箭头的单个方法,但我们可以使用andThen给我们的额外抽象级别。

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

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