30

Scalaの値に演算f: (T,T) => Tを適用できるようにしたい。2つの値のいずれかがである場合Option[T]の結果が必要です。NoneNone

より具体的には、次のことを行うためのより短い方法があるかどうかを知りたいです。

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]

4

6 に答える 6

34
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
于 2010-04-26T09:56:40.743 に答える
19

@RahulGの答えOptionは、モナドであるという事実を利用しています(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) {_ + _}

主な違いは、モナディック計算では、計算の失敗(つまりNone)がa評価を短絡させることです。適用スタイルでは、aとの両方bが評価され、両方がSomesの場合、純粋関数が呼び出されます。aaまた、モナディック計算では、値が計算に使用された可能性があることもわかりますb。適用バージョンでbは、の結果に依存することはできませんa

于 2010-04-26T11:33:03.777 に答える
3

私はレトロニムよりも少し古いバージョンのscalazを持っていますが、以下は例として私のために機能し、 1つだけではなく3つのタイプがある場合に一般化できます。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])
}

次に、次を追加できます。

val opt3 = none[Int]
val res2 = (opt1 <|*|> opt3).map(f.tupled)
println(res2) //None
于 2010-04-26T12:09:34.763 に答える
1

を開始するとScala 2.13Option#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
于 2019-02-08T21:26:44.190 に答える
0

あなたは理解のために使うことができます:

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)}}

これは、オプションがモナドであるためにも可能です。

于 2010-04-26T13:52:25.253 に答える
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)]になります(オプションからのものであるため、最大で1つの要素を使用します)。 headOption次に、最初の要素をオプションとして返します。

于 2017-11-08T16:49:10.973 に答える