使用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
答案 0 :(得分:12)
暂时搁置实施细节,map
andThen
用于函数(在A => ?
的函子实例下),并不是真的如果我们特别谈论的是函数而不是更高级别的抽象,那么谈论一个优先于另一个是很有意义的。
像map
这样的方法(以及更普遍的Functor
类型类)允许我们对特定类型或类型构造函数进行抽象。例如,假设我们要编写一个适用于incrementResult
或A => Int
的{{1}}方法。这些类型在继承方面没有任何共同点(缺少Kleisli[Option, A, Int]
,这是无用的),但AnyRef
和A => ?
都是仿函数,所以我们可以这样写:< / 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
。