17

2つのオプションがあり、両方がSomeの場合は、1つのコードパスを実行し、注意する場合は別のコードパスを実行するとします。のようなことをしたい

for (x <- xMaybe; y <- yMaybe) {
  // do something
}
else {
  // either x or y were None, handle this
}

ifステートメントまたはパターンマッチング(3つ以上のオプションがある場合はスケーリングされない可能性があります)以外に、これを処理するためのより良い方法はありますか?

4

9 に答える 9

26

オプションで出力yieldをラップするために使用することにより、構文提案に非常に近い:for

val result = { 
  for (x <- xMaybe; y <- yMaybe) yield {
    // do something
  }
} getOrElse {
  // either x or y were None, handle this
}

ブロックは、getOrElse一方または両方のオプションがNoneの場合にのみ実行されます。

于 2011-07-31T19:13:46.667 に答える
13

Options両方を同時にパターンマッチさせることができます。

(xMaybe, yMaybe) match {
  case (Some(x), Some(y)) => "x and y are there"
  case _ => "x and/or y were None"
}
于 2011-07-31T17:57:15.967 に答える
7

traverseScalazの関数は、ここで問題を一般化します。2つの引数が必要です。

  1. T[F[A]]
  2. A => F[B]

を返しますF[T[B]]。はTなどのトラバース可能なデータ構造でListあり、Fはなどの適用可能なファンクターOptionです。したがって、専門化するために、目的の関数は次のタイプになります。

  • List[Option[A]] => (A => Option[B]) => Option[List[B]]

だからあなたのすべてのOption価値観をList

  • val z = List(xMaybe, yMaybe)

結果を収集したい方法で取得した関数を作成します。

  • val f:X => Option [Y]=..。

と電話traverse

  • val r=zトラバースf

このプログラミングパターンは非常に頻繁に発生します。それについてすべてを語っている論文、The Essence oftheIteratorPatternがあります。

注:URLを修正したかったのですが、CLEVER編集ヘルプで少なくとも6文字を変更する必要があると言われるので、この便利なリンクも含めます(scalaの例):
http ://etorreborre.blogspot.com/2011/06/ essence-of-iterator-pattern.html

于 2011-07-31T21:10:57.680 に答える
5

なぜこのようなものが機能しないのでしょうか?

val opts = List[Option[Int]](Some(1), None, Some(2))
if (opts contains None) {
  // Has a None
} else {
  // Launch the missiles
  val values = opts.map(_.get) // We know that there is no None in the list so get will not throw
}
于 2011-07-31T17:57:48.313 に答える
4

扱っている値の数がわからない場合は、Tonyの答えが最適です。扱っている値の数がわかっている場合は、アプリケーションファンクターを使用することをお勧めします。

((xMaybe |@| yMaybe) { (x, y) => /* do something */ }).getOrElse(/* something else */)
于 2011-07-31T21:30:08.003 に答える
3

ソリューションをスケーラブルにしたいとおっしゃいました:

val optional = List(Some(4), Some(3), None)

if(optional forall {_.isDefined}) {
    //All defined
} else {
    //At least one not defined
}

編集:EmilIvanovソリューションがもう少しエレガントであることがわかりました。

于 2011-07-31T18:15:11.430 に答える
0

多くのオプションにスケーリングするには、次の線に沿って何かを試してください。

 def runIfAllSome[A](func:(A)=>Unit, opts:Option[A]*) = {
   if(opts.find((o)=>o==None) == None) for(opt<-opts) func(opt.get)
 }

これにより、次のことができます。

scala> def fun(i:Int) = println(i)
fun: (i: Int)Unit

scala> runIfAllSome(fun, Some(1), Some(2))
1
2

scala> runIfAllSome(fun, None, Some(1))

scala>
于 2011-07-31T17:59:06.193 に答える
0

ここで重要なのは、タイプの観点から、やりたいことを考えることだと思います。私が理解しているように、オプションペアのリストを繰り返し処理してから、特定の条件に基づいて何かを実行する必要があります。それで、あなたの質問の興味深い部分は、あなたが除いて、リターンタイプはどのように見えるでしょうか?次のようになると思います:Either [List [Option]、List [Option、Option]]。エラー側(左)では、Noneとペアになっている(いわばそのままにしておいた)オプションを累積します。右側では、成功した値を表す空でないオプションを合計します。したがって、まさにそれを実行する関数が必要になります。各ペアを検証し、その結果(成功-失敗)に従って累積します。これがお役に立てば幸いです。そうでない場合は、ユースケースについて詳しく説明してください。http://applicative-errors-scala.googlecode.com/svn/artifacts/0.6/pdf/index.pdfおよび: http: //blog.tmorris.net/automated-validation-with-applicatives-and-semigroups-for -sanjiv /

于 2011-08-01T08:18:23.073 に答える
0

から始めて、代わりに、両方のオプションが定義されている場合、またはなしの場合、2つのオプションをそれらの値のいくつかのタプルに連結するをScala 2.13使用できます。Option#zip

opt1 zip opt2 match {
  case Some((x, y)) => "x and y are there"
  case None         => "x and/or y were None"
}

またはOption#fold

(opt1 zip opt2).fold("x and/or y were None"){ case (x, y) => "x and y are there" }
于 2019-06-08T07:00:53.897 に答える