我希望能够在Scala中将操作f: (T,T) => T
应用于Option[T]
值。如果两个值中的任何一个为None
,我希望结果为None
。
更具体地说,我想知道是否有更短的方法来执行以下操作:
def opt_apply[T](f: (T,T) => T, x: Option[T], y: Option[T]): Option[T] = {
(x,y) match {
case (Some(u),Some(v)) => Some(f(u,v))
case _ => None
}
}
我已尝试(x zip y) map {case (u,v) => f(u,v)}
,但结果为Iterator[T]
而不是Option[T]
。
答案 0 :(得分:31)
scala> val (x, y) = (Some(4), Some(9))
x: Some[Int] = Some(4)
y: Some[Int] = Some(9)
scala> def f(x: Int, y: Int) = Math.max(x, y)
f: (x: Int,y: Int)Int
scala> for { x0 <- x; y0 <- y } yield f(x0, y0)
res26: Option[Int] = Some(9)
scala> val x = None
x: None.type = None
scala> for { x0 <- x; y0 <- y } yield f(x0, y0)
res27: Option[Int] = None
答案 1 :(得分:18)
@RahulG 的回答利用Option
是monad的事实(即使在Scala库中没有类型来表示这一点)。编译器将for
理解扩展为以下内容:
def a: Option[Int]
def b: Option[Int]
val calc: Option[Int] = a flatMap {aa => b map {bb => aa + bb}}
在Scalaz的帮助下,您还可以将其视为一个应用程序仿函数:
import scalaz._
import Scalaz._
def a: Option[Int]
def b: Option[Int]
val calc: Option[Int] = (a ⊛ b) {_ + _}
一个关键的区别在于,在monadic计算中,计算None
的失败(即a
)会使评估短路。在applicative样式中,a
和b
都被评估,如果两者都是Some
s,则调用pure函数。您还可以看到,在monadic计算中,值aa
可能已用于计算b
;在应用版本中,b
不能取决于a
的结果。
答案 2 :(得分:3)
我的 scalaz 版本比反名词略长,但以下内容适用于我作为示例,并且适用于您有3种类型{{1而不只是一个:
T, U, V
然后我可以添加:
def main(args: Array[String]) {
import scalaz._
import Scalaz._
val opt1 = some(4.0) //Option[Double]
val opt2 = some(3) //Option[Int]
val f: (Double, Int) => String = (d, i) => "[%d and %.2f]".format(i, d)
val res = (opt1 <|*|> opt2).map(f.tupled)
println(res) //Some([3 and 4.00])
}
答案 3 :(得分:1)
你可以用于理解:
def opt_apply[T](f: (T,T) => T, x: Option[T], y: Option[T]): Option[T] =
for (xp <- x; yp <- y) yield (f(xp,yp))
糖是:
x flatMap {xp => y map {yp => f(xp, yp)}}
由于Option是Monad
,这也是可能的答案 4 :(得分:0)
def optApply[A,B,C](f: (A, B) => C, a: Option[A], b: Option[B]): Option[C] =
a.zip(b).headOption.map { tup => f.tupled(tup) }
a.zip(b)
会导致Iterable [(A,B)](因为它来自Options,最多只有一个元素)。 headOption
然后返回第一个元素作为选项。
答案 5 :(得分:0)
可以将Scala 2.13
,Option#zip
开头的另一个Option
应用于返回Option
(在早期版本中,它会返回Iterable
);因此:
def optApply[T](f: (T,T) => T, a: Option[T], b: Option[T]): Option[T] =
a.zip(b).map(f.tupled)
zip
的行为是:
Some(2).zip(Some(3)) // Some((2, 3))
Some(2).zip(None) // None
None.zip(Some(3)) // None
None.zip(None) // None
,可以这样应用:
optApply[Int]((a, b) => a max b, Some(2), Some(5)) // Some(5)
optApply[Int]((a, b) => a max b, Some(2), None) // None