3

透過的に Scala オプションと通常の変数を組み合わせた条件文を書きたいと思います。例えば:

var o1 = Some(1)
var o2: Option[Int] = None

var x = 2

val test1 = x < 3 && o1<5  //=> should be true or Some(true)
val test2 = x < 3 && o2<5  //=> should be false or None
val test3 = x < 3 || o2<5  //=> should be true (o2 not evaluated)

もちろん、私は書くことができました

 test1 = x < 3 && o1.exists (_<5)

しかし、私はよりクリーンな構文を好むでしょう。

ヒントはありますか?'Option' を演算子で展開するか、暗黙的または圏論などを使用する必要がありますか?

EDIT : 宣言を修正しました。

4

5 に答える 5

4

Option[Int]からへのマッピングはどうOption[Boolean]ですか?

x < 3 && (o1 map {_ < 5} getOrElse false)
x < 3 && (o2 map {_ < 5} getOrElse false)
x < 3 || (o2 map {_ < 5} getOrElse false)
于 2012-05-20T21:35:09.673 に答える
4

暗黙の使用は確かに簡単です。

implicit def enrichOptionInt(self: Option[Int]) = new {
  def <(i: Int) = self.exists(_ < i)
}

val test1 = x < 3 && o1 < 5  // True

または、あらゆる種類の数値で機能させたい場合:

class EnrichedOptionNumeric[N: Numeric](self: Option[N]) {
  def <(n: N) = self.exists(v => implicitly[Numeric[N]].lt(v, n))
}
implicit def enrichOptionNumeric[N: Numeric](self: Option[N]) = new EnrichedOptionNumeric(self)

val oD = Some(2.0)
val test1 = x < 3 && o1 < 5    // true
val testD = x < 3 && oD < 5.0  // true

コメントで質問に答える編集:

同等性をサポートしたい場合、残念ながら、==その演算子は に対して既に定義されているため、使用できませんOption。メソッド (または演算子) がクラスに対して既に定義されている場合、Scala は呼び出されたメソッドを認識しない場合にのみ暗黙を検索するため、暗黙は決してトリガーされません。

ただし、単に別の記号を定義して、「オプションが等しい」ことを意味するようにすることもできます。たとえば、 を使用できます===EnrichedOptionNumericそのためには、上記の定義に次の行を追加するだけです。

def ===(n: N) = self.exists(v => implicitly[Numeric[N]].equiv(v, n))

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

val testE = x < 3 && o1 === 1 // true
于 2012-05-20T21:31:21.157 に答える
1

を使用するよりも、この問題のコンテキストで「欠落している」値を表現するより自然な方法があるかどうかを考えてくださいOption。たぶん、制限はない、Doubleの値Infinityが機能する、またはのあるIntと言うことができInteger.MAX_VALUEます。Option次に、問題から完全に削除します。できない場合は、使用することができます

var o1 = Some (1)
var o2 = Option[Int] = None

var x = 2

val test1 = x < 3 && o1.getOrElse(Integer.MAX_VALUE)<5  //=> should be true or Some(true)
val test2 = x < 3 && o2.getOrElse(Integer.MAX_VALUE)<5  //=> should be false or None
val test3 = x < 3 || o2.getOrElse(Integer.MAX_VALUE)<5  //=> should be true (o2 not evaluated)
于 2012-05-20T22:37:26.283 に答える
1

Tomasz Nurkiewicz の答えは、 Scalazシュガーを使用してより簡潔にすることができMonoidますBoolean

モノイドの「ゼロ」値はfalseであるため、scalaz で定義された単項演算子を使用してにo getOrElse falseなります。(ここでは scalaz 6.0.4 を使用しています)~o~

def p: Int => Boolean = _ < 3
def q: Int => Boolean = _ < 5
import scalaz._, Scalaz._

scala> val test1 = p(x) && ~(o1 map q)
test1: Boolean = true

scala> val test2 = p(x) && ~(o2 map q)
test2: Boolean = false

scala> val test3 = p(x) || ~(o2 map q)
test3: Boolean = true
于 2012-05-21T07:08:26.247 に答える
1

Ordering[A] がある場合、Scala は実際に Option[A] の Ordering を作成できますが、セマンティクスは必要なものとは異なります (None が最小値です)。

また、比較が機能するには、両方の値が同じ型である必要があるため、Ints を Option に持ち上げる方法が必要です。そのために opt メソッドを追加しました。

これは、内部順序付けの例です。

import scala.math.Ordering.Implicits.infixOrderingOps
//This allows you to use method/operator syntax on anything with an Ordering

implicit def mkOption[A](a: A) = new { def opt: Option[A] = Some(a) }

var o1 = Some(1)
var o2: Option[Int] = None

var x = 2

val test1 = x < 3 && o1<5.opt  //=> true
val test2 = x < 3 && o2<5.opt  //=> true
val test3 = x < 3 || o2<5.opt  //=> true
None > 0.opt //=> false
None < 0.opt //=> true

セマンティクスに近づくために、新しい順序を定義できます

implicit def mkOptionOrdering[A: Ordering] = new Ordering[Option[A]] {
    def compare(a: Option[A], b: Option[A]): Int = {
      if (a.isEmpty || b.isEmpty) 0 
      else implicitly[Ordering[A]].compare(a.get, b.get)
    }
  }

これで、テストは期待どおりに機能し、2 つの追加のテストも false になりますが、これらのセマンティクスはかなり奇妙です。compare は、等しくないものに対して 0 を返します。

于 2012-05-23T04:16:37.443 に答える