Mix Scala Option and regular variable in the statement

I would like to write conditional expressions that mix Scala Parameters and regular variables transparently. For instance:

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)

of course i could write

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

but I would prefer a cleaner syntax.

Any hint? Should I extend the "Option" with operators or use implicits, or category theory or otherwise?

EDIT: Amended Declaration.

+3
source share
5 answers

Using implicits is, of course, easy:

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

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

Or, if you want it to work for any type of Numeric:

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

EDIT to answer the question in the comment:

, , , ==, Option. ( ) , , Scala , .

, "option equals". , ===. , EnrichedOptionNumeric :

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

:

val testE = x < 3 && o1 === 1 // true
+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)
+4

, "" , Option. , , a 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)
+1

Tomasz Nurkiewicz Scalaz Monoid Boolean.

"" false, o getOrElse false ~o, ~, scalaz. ( scalaz 6.0.4)

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
+1

Scala can actually do Ordering for Option [A] if you have Ordering [A], but the semantics are different (None is the smallest value) from what you wanted.

In addition, to compare with the work, both values ​​must be of the same type, so you need a way to raise Ints in Option. I have added the opt method for this purpose.

This is an example with internal ordering:

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

To get closer to semantics, we can define a new order

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

Now your tests will do what you expected, and 2 additional tests will also be false, but these semantics are pretty odd, the comparison returns 0 for things that are not equal.

+1
source

All Articles