Jus12
Jus12

Reputation: 18034

How to use sum for lists of custom types?

Refer to below snippet:

class Foo(val b:BigDecimal) {
  def +(f:Foo) = new Foo(b+f.b) 
}
val l = List(new Foo(1), new Foo(2))

l.sum // gives error: could not find implicit value for parameter num: Numeric[Foo]

What is the easiest way to get this to work? I know I have to define some implicit conversions.

Note: the class Foo is inside a library so I cannot edit that code. I need to do it outside Foo.

I could not find answer to this particular case despite there being several examples of using Numeric types

Upvotes: 2

Views: 75

Answers (2)

Dmytro Mitin
Dmytro Mitin

Reputation: 51693

You can define necessary implicit:

  class Foo(val b:BigDecimal) {
    def +(f:Foo) = new Foo(b+f.b)
  }
  object Foo {
    implicit val numericFoo: Numeric[Foo] = new Numeric[Foo] {
      override def plus(x: Foo, y: Foo): Foo = new Foo(x.b + y.b)
      override def minus(x: Foo, y: Foo): Foo = new Foo(x.b - y.b)
      override def times(x: Foo, y: Foo): Foo = new Foo(x.b * y.b)
      override def negate(x: Foo): Foo = new Foo(-x.b)
      override def fromInt(x: Int): Foo = new Foo(x)
      override def toInt(x: Foo): Int = x.b.toInt
      override def toLong(x: Foo): Long = x.b.toLong
      override def toFloat(x: Foo): Float = x.b.toFloat
      override def toDouble(x: Foo): Double = x.b.toDouble
      override def compare(x: Foo, y: Foo): Int = x.b.compare(y.b)
    }
  }

or just

implicit val numericFoo: Numeric[Foo] = new Numeric[Foo] {
  override def plus(x: Foo, y: Foo): Foo = x + y
  override def minus(x: Foo, y: Foo): Foo = ???
  override def times(x: Foo, y: Foo): Foo = ???
  override def negate(x: Foo): Foo = ???
  override def fromInt(x: Int): Foo = new Foo(x)
  override def toInt(x: Foo): Int = ???
  override def toLong(x: Foo): Long = ???
  override def toFloat(x: Foo): Float = ???
  override def toDouble(x: Foo): Double = ???
  override def compare(x: Foo, y: Foo): Int = ???
}

Or you can define your own extension method

  implicit class FooList(foos: List[Foo]) {
    def sum1: Foo = foos.foldLeft(new Foo(0))(_ + _)
  }

  l.sum1

Upvotes: 3

Joe K
Joe K

Reputation: 18434

The full signature for List's sum method is:

def sum[B >: A](implicit num: Numeric[B]): B

So you must provide an implicit Numeric for your class, or some superclass of your class:

implicit val fooNumeric = new Numeric[Foo] {
  def compare(x: Foo, y: Foo): Int = ???
  def plus(x: Foo, y: Foo): Foo = ???
  ... other methods ...
}

My guess is sum only needs plus to work correctly, but you'll at least have to give a dummy implementation of the other abstract Numeric methods to get it to compile.

Upvotes: 2

Related Questions