This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Option[Double] arithmetic operators

6 replies
azzoti
Joined: 2008-12-23,
User offline. Last seen 3 years 8 weeks ago.

Suppose d1, d2, d3 d4 are all Option[Double]

One way of doing arithmetic with Option[Double] values so that the
expression returns None if any of the values is None is as follows:

val result: Option[Double] =
for (a <- d1; b <- d2; c <- d3; d <- d4)
yield (a+b+c+d)/ 4;

Clever, yes, but it sucks from a readability point of view.
AND you have to ALIAS all variables.

Is there a more readable way of doing this?

Would it be possible to define +-/* etc etc for Option[Double] Option[Int]
etc.
Has anybody done this already somewhere?

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: Option[Double] arithmetic operators

On Thu, Oct 22, 2009 at 12:38:10PM -0700, Tim Azzopardi wrote:
> val result: Option[Double] =
> for (a <- d1; b <- d2; c <- d3; d <- d4)
> yield (a+b+c+d)/ 4;
>
> Clever, yes, but it sucks from a readability point of view.
> AND you have to ALIAS all variables.
>
> Is there a more readable way of doing this?

I don't know if it's any more readable, but you can avoid aliasing any
number of ways:

val list: List[Option[Double]]

list.flatten match {
case xs if xs.size == list.size => Some(xs.sum / xs.size)
case _ => None
}

If you're following the thread on some scala list about
map/fmap/cofmap/on/by, it suddenly becomes relevant here because one of
the "cofmaps" I wrote on Numeric was an implicit which created
Numeric[Option[T]] from Numeric[T]. It would propagate None but
otherwise do the math. Pretty seamless as I recall, but I wrote it
months ago and haven't come back.

ichoran
Joined: 2009-08-14,
User offline. Last seen 2 years 3 weeks ago.
Re: Option[Double] arithmetic operators
It's worth noting that Not-a-Number already has this behavior (in hardware).  Unfortunately, RichDouble doesn't contain an isNaN method for testing, but java.lang.Double does.

I hate recommending a shift from Option to value-based success/failure, but if you want higher performance numeric code, this might be the way to go.

If you just want elegant and correct code, the easiest way pre-2.8 (and possibly still the clearest post-2.8) is to use the standard pimping pattern (shown here with a trick to shortcut evaluations when the first argument is None; it's perfectly okay to test for o==None || od==None in RichOptionDouble instead of making the subclassed RichNoneDouble object, though):

class RichOptionDouble(od:Option[Double]) {
  def +(o:Option[Double]) = if (o==None) o else Some(o.get+od.get)
  def unary_-() = Some(-od.get)
  def -(o:Option[Double]) = if (o==None) o else Some(o.get+od.get)
  // Same deal for *, /
}

object RichNoneDouble extends RichOptionDouble(None) {
  override def +(o:Option[Double]) = None
  override def unary_-() = None
  override def -(o:Option[Double]) = None
  // Same deal for *, /
}

implicit def optiondouble2richoptiondouble(od:Option[Double]) = {
  if (od==None) RichNoneDouble else new RichOptionDouble(od)
}

scala> Some(3.5)+Some(0.7)
res0: Option[Double] = Some(4.2)

scala> Some(4.4)+None
res1: Option[Double] = None

scala> -None
res2: Option[Double] = None

If you wanted to be really safe, you could check for isNaN also and turn those into RichNoneDoubles and/or None return types.

Also, as Paul mentions, one can use Numeric to avoid having to rewrite the math for each type as of 2.8.

  --Rex

On Thu, Oct 22, 2009 at 3:38 PM, Tim Azzopardi <tim@tigerfive.com> wrote:

Suppose d1, d2, d3 d4 are all Option[Double]

One way of doing arithmetic with Option[Double] values so that the
expression returns None if any of the values is None is as follows:

 val result: Option[Double] =
   for (a <- d1; b <- d2; c <- d3; d <- d4)
   yield (a+b+c+d)/ 4;

Clever, yes, but it sucks from a readability point of view.
AND you have to ALIAS all variables.

Is there a more readable way of doing this?

Would it be possible to define +-/* etc etc for Option[Double] Option[Int]
etc.
Has anybody done this already somewhere?


--
View this message in context: http://www.nabble.com/Option-Double--arithmetic-operators-tp26015945p26015945.html
Sent from the Scala - User mailing list archive at Nabble.com.


ichoran
Joined: 2009-08-14,
User offline. Last seen 2 years 3 weeks ago.
Re: Option[Double] arithmetic operators
Whoops, forgot to proofread for typos:

On Thu, Oct 22, 2009 at 5:41 PM, Rex Kerr <ichoran@gmail.com> wrote:

class RichOptionDouble(od:Option[Double]) {
  def +(o:Option[Double]) = if (o==None) o else Some(o.get+od.get)
  def unary_-() = Some(-od.get)
  def -(o:Option[Double]) = if (o==None) o else Some(o.get+od.get)
 
It's should be a minus sign inside the Some, of course:

  def -(o:Option[Double]) = if (o==None) o else Some(o.get - od.get)

--Rex
azzoti
Joined: 2008-12-23,
User offline. Last seen 3 years 8 weeks ago.
Re: Option[Double] arithmetic operators

Thanks, that looks like its exactly what I was looking for.

Rex Kerr-2 wrote:
>
> Whoops, forgot to proofread for typos:
>
> On Thu, Oct 22, 2009 at 5:41 PM, Rex Kerr wrote:
>
>>
>> class RichOptionDouble(od:Option[Double]) {
>> def +(o:Option[Double]) = if (o==None) o else Some(o.get+od.get)
>> def unary_-() = Some(-od.get)
>> def -(o:Option[Double]) = if (o==None) o else Some(o.get+od.get)
>>
>
> It's should be a minus sign inside the Some, of course:
>
> def -(o:Option[Double]) = if (o==None) o else Some(o.get - od.get)
>
> --Rex
>
>

Vadim
Joined: 2009-02-28,
User offline. Last seen 42 years 45 weeks ago.
Re: Option[Double] arithmetic operators
You can also check out the Applicative functor - implemented in scalaz (http://scalaz.googlecode.com/svn/artifacts/latest/demo/scalazdemo/control/Applicative.scala)

On Fri, Oct 23, 2009 at 12:53 AM, Tim Azzopardi <tim@tigerfive.com> wrote:

Thanks, that looks like its exactly what I was looking for.


Rex Kerr-2 wrote:
>
> Whoops, forgot to proofread for typos:
>
> On Thu, Oct 22, 2009 at 5:41 PM, Rex Kerr <ichoran@gmail.com> wrote:
>
>>
>> class RichOptionDouble(od:Option[Double]) {
>>   def +(o:Option[Double]) = if (o==None) o else Some(o.get+od.get)
>>   def unary_-() = Some(-od.get)
>>   def -(o:Option[Double]) = if (o==None) o else Some(o.get+od.get)
>>
>
> It's should be a minus sign inside the Some, of course:
>
>   def -(o:Option[Double]) = if (o==None) o else Some(o.get - od.get)
>
> --Rex
>
>

--
View this message in context: http://www.nabble.com/Option-Double--arithmetic-operators-tp26015945p26017843.html
Sent from the Scala - User mailing list archive at Nabble.com.


azzoti
Joined: 2008-12-23,
User offline. Last seen 3 years 8 weeks ago.
Re: Option[Double] arithmetic operators

Thanks to all for the replies. I have read and learnt from them.

I have used Rex Kerr's suggested approach. It is working well for me so far.

I have NOT dealt with null and isNaN in the code below.

I have NOT tried generalizing this using Numeric as suggested above.

I have used Jorge Ortiz's Scala-Time technique for managing imports and
implicits

I have used the latest nightly eclipse plugin using the 2.8pre compiler. No
idea if it works on earlier versions.

============ File: RichOptionDouble.scala ============
package org.scala_tools.option.math

// Modelled on Martin Odersky pimp my library technique
// http://www.artima.com/weblogs/viewpost.jsp?thread=179766

class RichOptionDouble(od:Option[Double]) {
def +(o:Option[Double]) = if (o==None) o else Some(od.get+o.get)
// Without the :Option[Double] in the definition of unary_-(),
RichNoneDouble unary_-()
// doesn't compile as it expects to return Some[Double]
def unary_-():Option[Double] = Some(-od.get)
def -(o:Option[Double]) = if (o==None) o else Some(od.get-o.get)
def *(o:Option[Double]) = if (o==None) o else Some(od.get*o.get)
def /(o:Option[Double]) = if (o==None) o else Some(od.get/o.get)
}

object RichNoneDouble extends RichOptionDouble(None) {
override def +(o:Option[Double]) = None
override def unary_-() = None
override def -(o:Option[Double]) = None
override def *(o:Option[Double]) = None
override def /(o:Option[Double]) = None
}
==========================================

================= File: Implicits.scala ============
package org.scala_tools.option.math

// Modeled on technique in Scala-Time

object Implicits extends Implicits

trait Implicits {
implicit def optiondouble2richoptiondouble(od:Option[Double]) = {
if (od==None) RichNoneDouble else new RichOptionDouble(od)
}
implicit def double2optiondouble(d:Double) = Some(d)
implicit def int2optiondouble(i:Int) = Some(i.toDouble)
}
==========================================

================= File: Imports.scala ============
package org.scala_tools.option.math

// Modelled on technique in Scala-Time
object Imports extends Imports

trait Imports extends Implicits
==========================================

Usage

import org.scala_tools.option.math.Imports._

object Foo {
def main(args : Array[String]) : Unit = {
val d1 = Some(1d)
val d2 = Some(2d)
val dn = None
val i:Int = 1;

println(d1 + d2)
println(d1 + dn)
println(dn + d1)
println

println(d1 + d2 + dn)
println(d1 + dn + d2)
println(dn + d1 + d2)
println

println(d1 + d2 + 3)
println(d1 + 3 + d2)
// println(3 + d1 + d2) does not compile
println(Some(3.0) + d1 + d2) // is ok
println

println(d1 + d2 + 3.0)
println(d1 + 3.0 + d2)
// println(3.0 + d1 + d2) does not compile
println(Some(3.0) + d1 + d2) // is ok
println
}
}

outputs:

Some(3.0)
None
None

None
None
None

Some(6.0)
Some(6.0)
Some(6.0)

Some(6.0)
Some(6.0)
Some(6.0)

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland