Scala: What is the best way to do numerical operations in generic classes?

In Scala, I would like to write generic classes that use type operators>, /, *, etc., but I don't see how to restrict T to make this work.

I looked at the T constraint using Ordered [T], but that doesn't seem to work, since only RichXXX (like RichInt) extends it, not Int, etc. I also saw Numeric [T], is it only available in Scala 2.8?

Here is an example:

class MaxOfList[T](list: List[T] ) { def max = { val seed: Option[T] = None list .map( t => Some(t)) // Get the max .foldLeft(seed)((i,m) => getMax(i,m) ) } private def getMax(x: Option[T], y: Option[T]) = { if ( x.isDefined && y.isDefined ) if ( x > y ) x else y else if ( x.isDefined ) x else y } } 

This class will not compile, because there are many Ts that do not support> etc.

Thoughts?

Now I used the MixIn tag to get around this:

 /** Defines a trait that can get the max of two generic values */ trait MaxFunction[T] { def getMax(x:T, y:T): T } /** An implementation of MaxFunction for Int */ trait IntMaxFunction extends MaxFunction[Int] { def getMax(x: Int, y: Int) = x.max(y) } /** An implementation of MaxFunction for Double */ trait DoubleMaxFunction extends MaxFunction[Double] { def getMax(x: Double, y: Double) = x.max(y) } 

What if we change the original class, we can mix it during instance creation.

PS Mitch, inspired by your rewriting of getMax, is another one:

  private def getMax(xOption: Option[T], yOption: Option[T]): Option[T] = (xOption,yOption) match { case (Some(x),Some(y)) => if ( x > y ) xOption else yOption case (Some(x), _) => xOption case _ => yOption } 
+7
generics scala numerical
source share
3 answers

You can use View ratings .

In short, def foo[T <% U](t: T) is a function that will take any T that is either implicitly converted to U or can be implicitly converted. Since Int can be converted to RichInt (which contains your desired method), this is a great use case.

 class MaxOfList[T <% Ordered[T]](list: List[T] ) { def max = { val seed: Option[T] = None list.foldLeft(seed)(getMax(_,_)) } private def getMax(xOption: Option[T], y: T) = (xOption, y) match { case (Some(x), y) if ( x > y ) => xOption case (_, y) => Some(y) } } 

PS - I rewrote the getMax (...) method to compare values ​​instead of the parameters themselves and used pattern matching instead of isDefined (...)

PPS - Scala 2.8 will have a numerical attribute that may be useful. http://article.gmane.org/gmane.comp.lang.scala/16608


Adding

Just for a giggle, here's a supercompact version that completely eliminates the getMax method:

 class MaxOfList[T <% Ordered[T]](list: List[T] ) { def max = list.foldLeft(None: Option[T]) { case (Some(x), y) if ( x > y ) => Some(x) case (_, y) => Some(y) } } 

Another addition

This version would be more efficient for large lists ... avoids creating Some (x) for each element:

 class MaxOfList[T <% Ordered[T]](list: List[T] ) { def max = { if (list.isEmpty) None else Some(list.reduceLeft((a,b) => if (a > b) a else b)) } } 

Last, I promise!

At this point, you can simply drop the class and use the function:

  def max[T <% Ordered[T]](i: Iterable[T]) = { if (i.isEmpty) None else Some(i.reduceLeft((a,b) => if (a > b) a else b)) } 
+9
source share

With Numeric[T] in scala 2.8,

 scala> case class MaxOfList[T : Numeric](list: List[T]) { | def max = if(list.isEmpty) None else Some(list.max) | } defined class MaxOfList scala> MaxOfList(1::2::3::9::7::Nil).max res1: Option[Int] = Some(9) scala> MaxOfList(1.5::3.9::9.2::4.5::Nil).max res2: Option[Double] = Some(9.2) scala> MaxOfList(Nil: List[Byte]).max res3: Option[Byte] = None scala> 
+2
source share

As Mitch Blevins answered, what were done in terms of limitations. Now, while Numeric has added something only in Scala 2.8, not that it does not depend on any Scala 2.8 feature. You can do the same on Scala 2.7.

You might be interested in some common code snippets that I wrote for Rosetta Code :

+1
source share

All Articles