我只是想补充一点,提升函数可以用作映射到functor的替代方法。例如,如果您有 2 个Option[Int]
要应用f1
的对象,您可以这样做:
val sum: Option[Int] = option1.flatMap { x => option2.map{ y => x + y } }
请注意,结果是Option[Int]
. 正如 Alexey Romanov 所说,返回类型f2
也应该是Option
. 的全部意义Option
在于让您对值进行操作而不必担心NullPointerException
s 或其他错误,因为该值不存在。
但是,这种映射有点冗长,而且必须决定何时需要使用flatMap
和map
. 这时候起重就派上用场了。
让我们定义f2
一个更好的处理None
s:
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) => Int
to (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
和C
are all Int
for f1
)并返回另一个类型的函数(Option[A], Option[B]) => Option[C]
。现在,我们不必再使用那些尴尬的嵌套map
s 和flatMap
s 了。你可以这样做:
val sum: Option[Int] = lift2(f1)(option1, option2)
当然,您也可以定义lift3
、lift4
等,但只定义一个lift1
函数并使用柯里化来完成其余部分可能更容易。
当然,lift
如果您知道如何拆开和组装您要提升到的类型,您只能使用一个函数。例如,如果Some
是一个具有私有unapply
方法的对象,并且不可能对其进行模式匹配,那么您将无法提升f1
. 如果 for 的构造函数Some
是私有的并且你不可能创建 new Option
s,也会发生同样的情况。
编辑:这是您如何将多个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
}