Search code examples
scalagenericstype-inferencetypeclasszero

How to use Numeric[T] to represent zero of any numeric type


I have a piece of Scala code that I'd like to make more generic. I know that Numeric[T] exists, but I'm not sure how to use it.

  def sumMaps[A](m1: Map[A, Long], m2: Map[A, Long]): Map[A, Long] = {
    m1 ++ m2.map { case (k, v) => k -> (v + m1.getOrElse(k, 0L)) }
  }

  def sumMaps[A](m1: Map[A, Int], m2: Map[A, Int]): Map[A, Int] = {
    m1 ++ m2.map { case (k, v) => k -> (v + m1.getOrElse(k, 0)) }
  }

  def sumMaps[A](m1: Map[A, Double], m2: Map[A, Double]): Map[A, Double] = {
    m1 ++ m2.map { case (k, v) => k -> (v + m1.getOrElse(k, 0)) }
  }

I'd like to write something like this (just once), where the zero value gets auto-converted to a B type.

  def sumMaps[A, B: Numeric[?]](m1: Map[A, B], m2: Map[A, B]): Map[A, B] = {
    m1 ++ m2.map { case (k, v) => k -> (v + m1.getOrElse(k, 0)) }
  }

Solution

  • Try

    def sumMaps[A, B](m1: Map[A, B], m2: Map[A, B])(implicit num: Numeric[B]): Map[A, B] = {
      m1 ++ m2.map { case (k, v) => k -> num.plus(v, m1.getOrElse(k, num.zero)) }
    }
    

    or

    import Numeric.Implicits._
    def sumMaps[A, B](m1: Map[A, B], m2: Map[A, B])(implicit num: Numeric[B]): Map[A, B] = {
      m1 ++ m2.map { case (k, v) => k -> (v + m1.getOrElse(k, num.zero)) }
    }
    

    or

    def sumMaps[A, B: Numeric](m1: Map[A, B], m2: Map[A, B]): Map[A, B] = {
      val num = implicitly[Numeric[B]]
      import num._
      m1 ++ m2.map { case (k, v) => k -> (v + m1.getOrElse(k, zero)) }
    }
    

    The imports provide implicit conversion infixNumericOps

    m1 ++ m2.map { case (k, v) => k -> (infixNumericOps(v) + m1.getOrElse(k, num.zero)) }
    

    so we do not have to explicitly use Numeric.plus like in the first example.