我只是想补充一点,提升函数可以用作映射到functor的替代方法。例如,如果您有 2 个Option[Int]要应用f1的对象,您可以这样做:
val sum: Option[Int] = option1.flatMap { x => option2.map{ y => x + y } }
请注意,结果是Option[Int]. 正如 Alexey Romanov 所说,返回类型f2也应该是Option. 的全部意义Option在于让您对值进行操作而不必担心NullPointerExceptions 或其他错误,因为该值不存在。
但是,这种映射有点冗长,而且必须决定何时需要使用flatMap和map. 这时候起重就派上用场了。
让我们定义f2一个更好的处理Nones:
def f2(a: Option[Int], b: Option[Int]): Option[Int] =
a match {
case Some(x) => b match {
case Some(y) => Some(x + y)
case None => None
}
case None => None
}
f1我们也可以通过替换x + y来定义它f1(x + y)
def f2(a: Option[Int], b: Option[Int]): Option[Int] =
a match {
case Some(x) => b match {
case Some(y) => Some(f1(x, y))
case None => None
}
case None => None
}
现在,f2不需要知道如何添加数字,它只是f1用来添加它们。事实上,我们甚至可以制作f1的参数f2。
def f2(f1: (Int, Int) => Int)(a: Option[Int], b: Option[Int]): Option[Int] =
a match {
case Some(x) => b match {
case Some(y) => Some(f1(x, y))
case None => None
}
case None => None
}
看看那里发生了什么?我们只是习惯于f2“提升”f1从(Int, Int) => Intto (Option[Int], Option[Int]) => Option[Int]。让我们重命名它lift2,实际上。我们还可以使它更通用:
def lift2[A, B, C](f1: (A, B) => C)(a: Option[A], b: Option[B]): Option[C] =
a match {
case Some(x) => b match {
case Some(y) => Some(f1(x, y))
case None => None
}
case None => None
}
lift2现在是一个函数,它接受一个类型的函数(A, B) => C(这里是A,B和Care all Intfor f1)并返回另一个类型的函数(Option[A], Option[B]) => Option[C]。现在,我们不必再使用那些尴尬的嵌套maps 和flatMaps 了。你可以这样做:
val sum: Option[Int] = lift2(f1)(option1, option2)
当然,您也可以定义lift3、lift4等,但只定义一个lift1函数并使用柯里化来完成其余部分可能更容易。
当然,lift如果您知道如何拆开和组装您要提升到的类型,您只能使用一个函数。例如,如果Some是一个具有私有unapply方法的对象,并且不可能对其进行模式匹配,那么您将无法提升f1. 如果 for 的构造函数Some是私有的并且你不可能创建 new Options,也会发生同样的情况。
编辑:这是您如何将多个Option[Int]对象与函数一起添加f1的lift2方法。
val f2 = lift2(f1)
val optionSum = f2(f2(option1, option2), option3)
没有 f2,它看起来像这样
val sum1 = option1 match {
case Some(x) => option2 match {
case Some(y) => Some(f1(x, y))
case None => None
}
case None => None
}
val finalSum = sum1 match {
case Some(x) => option3 match {
case Some(y) => Some(f1(x, y))
case None => None
}
case None => None
}