如何在Scala中组合选项值?

Jef*_*eff 29 scala type-conversion scalaz

我希望能够将操作f: (T,T) => T应用于Option[T]Scala中的值.我希望结果是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
  }
}
Run Code Online (Sandbox Code Playgroud)

我试过了,(x zip y) map {case (u,v) => f(u,v)}但结果Iterator[T]却不是Option[T].

mis*_*tor 33

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
Run Code Online (Sandbox Code Playgroud)


ret*_*nym 19

@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}}
Run Code Online (Sandbox Code Playgroud)

在Scalaz的帮助下,您还可以将其视为一个应用程序仿函数:

import scalaz._
import Scalaz._

def a: Option[Int]
def b: Option[Int]
val calc: Option[Int] = (a ? b) {_ + _}
Run Code Online (Sandbox Code Playgroud)

一个关键的区别在于,在monadic计算中,计算的失败(即None)a会使评估短路.在应用性的风格,无论是ab被评估,如果两者都是SomeS,纯函数被调用.您还可以看到,在monadic计算中,该值aa可能已用于计算中b; 在应用版本中,b不能取决于结果a.

  • 从第7版Scalaz ASCII别名到`⊛`运算符是`| @ |`:`val calc:Option [Int] =(a | @ | b){_ + _}` (2认同)