7

scala で、2 つの Option 引数の加算を定義するにはどうすればよいですか? 具体的に言うと、それらが型のラッパーであるとしましょうInt(私は実際に double のマップを扱っていますが、この例はより単純です)。

次のことを試しましたが、エラーが発生するだけです。

  def addOpt(a:Option[Int], b:Option[Int]) = {
    a match {
      case Some(x) => x.get
      case None => 0
    } + b match {
      case Some(y) => y.get
      case None => 0
    }
  }

追加するために編集:

私の実際の問題では、疎なベクトルの代用である 2 つのマップを追加しています。したがって、None の場合は Map[Int, Double] を返し、+ は実際には ++ です (stackoverflow.com/a/7080321/614684 で微調整を行います)。

4

5 に答える 5

26

モノイド

巨人の肩の上に立って、一般的な抽象化とそれらを使用するために構築されたライブラリを利用できることに気付くと、人生がずっと楽になるかもしれません。この目的のために、この質問は基本的に モノイドの取り扱いに関するものであり(これについては以下の関連する質問を参照してください)、問題のライブラリはscalazと呼ばれます。

scalaz FPを使用すると、これは次のようになります。

def add(a: Option[Int], b: Option[Int]) = ~(a |+| b)

さらに、これは任意のモノイドMで機能します。

def add[M: Monoid](a: Option[M], b: Option[M]) = ~(a |+| b)

さらに便利なことに、Foldableコンテナ内に配置されたそれらの任意の数で機能します。

def add[M: Monoid, F: Foldable](as: F[Option[M]]) = ~as.asMA.sum

Int明らかな、、を除いて、いくつかのかなり有用なモノイドは次のとおりであることに注意してStringくださいBoolean

  1. Map[A, B: Monoid]
  2. A => (B: Monoid)
  3. Option[A: Monoid]

実際、独自のメソッドを抽出することはほとんど価値がありません。

scala> some(some(some(1))) #:: some(some(some(2))) #:: Stream.empty
res0: scala.collection.immutable.Stream[Option[Option[Option[Int]]]] = Stream(Some(Some(Some(1))), ?)

scala> ~res0.asMA.sum
res1: Option[Option[Int]] = Some(Some(3))

いくつかの関連する質問

Q.モノイドとは何ですか?

モノイドは、結合二項演算とこの演算の下に単位元Mが存在する型であり、すべての型に対して(M, M) => MImplus(m, I) == m == mplus(I, m)mM

Q.とは何|+|ですか?

mplusこれは、二項演算の単なるscalazの省略形(またはASCIIマッドネス、ymmv)です。

Q.とは何~ですか?

これは、「またはアイデンティティ」を意味する単項演算子であり、scalazライブラリによって(scalaの暗黙の変換を使用して)モノイドのOption[M]ifに後付けされます。M明らかに、空でないオプションはその内容を返します。空のオプションは、モノイドのIDに置き換えられます。

Q.とは何asMA.sumですか?

AFoldableは基本的に、折りたたむことができるデータ構造です(foldLeftたとえば、など)。foldLeftシード値と操作を使用して、連続する計算を構成することを思い出してください。モノイドを合計する場合、シード値はIDIであり、操作はmplusです。asMA.sumしたがって、を呼び出すことができますFoldable[M : Monoid]asMA名前が標準ライブラリのsumメソッドと衝突するため、使用する必要がある場合があります。

いくつかの参考文献

  • 野生でモノイドを使用する実際的な例を示す、私が行った講演のスライドビデオ
于 2012-05-16T16:06:14.960 に答える
10
def addOpts(xs: Option[Int]*) = xs.flatten.sum

これは、任意の数の入力に対して機能します。

于 2012-05-16T12:17:09.540 に答える
5

どちらもデフォルトで 0 の場合、パターン マッチングは必要ありません。

  def addOpt(a:Option[Int], b:Option[Int]) = {
    a.getOrElse(0) + b.getOrElse(0)
  }
于 2012-05-16T12:00:33.273 に答える
4

(要求に応じて回答で上記のコメントを繰り返します)

オプションの内容を適切な方法で抽出していません。と一致する場合case Some(x)xはoption(type Int)内の値であり、それを呼び出さないでくださいget。ただやる

case Some(x) => x 

とにかく、コンテンツやデフォルトが必要な場合a.getOrElse(0)は、より便利です

于 2012-05-16T16:38:57.387 に答える
0
def addOpt(ao: Option[Int], bo: Option[Int]) =
    for {
        a <- ao
        b <- bo
    } yield a + b
于 2012-05-16T17:37:04.297 に答える