Working with numbers in a generic way. Parsing and

2019-08-12 08:39发布

问题:

So, Numeric[T] type class in scala allows operations +, -, and *. But it does not provide / operation and fromString :: String -> Option[T]. I have to write:

    abstract class NumParser[A] {
      def unapply(s: String): Option[A]
      def /(x: A, y: A): A
    }

    implicit val doubleParser = new NumParser[Double]() {
      import scala.util.Try
      def unapply(s: String): Option[Double] = Try(s.toDouble).toOption
      def /(x: Double, y: Double) = x / y
    }

    ...

Each time I need to work with numbers in a generic way.

Both operations are quite common and I wonder whether I'm missing something and they are implemented in scala or some other common library (like scalaz), and I just didn't notice that.

I am aware that scala has Fractional and Integral, which has /. But I can't use them simultaneously.

I'd like / op to be Int -> Int -> Int for Int and Double -> Double -> Double for Double

回答1:

So basically you want to be able to do two different things, division and quot (integer divsion), depending on the type. Then you would have to invent your own type class. You could simply wrap Integral and Fractional:

// prefer Integral over Fractional
trait LowPriStrangeDiv {
  implicit def fromFractional[A](implicit f: Fractional[A]): StrangeDiv[A] =
    new StrangeDiv[A] {
      def strangeDiv(a: A, b: A): A = f.div(a, b)
    }
}
object StrangeDiv extends LowPriStrangeDiv {
  implicit def fromIntegral[A](implicit i: Integral[A]): StrangeDiv[A] =
    new StrangeDiv[A] {
      def strangeDiv(a: A, b: A): A = i.quot(a, b)
    }
}
trait StrangeDiv[A] {
  def strangeDiv(a: A, b: A): A
}

Test:

implicit class DivSyntax[A](private val a: A) extends AnyVal {
  def / (b: A)(implicit d: StrangeDiv[A]) : A = d.strangeDiv(a, b)
}

def test[A: StrangeDiv](a: A, b: A): A = a / b

assert(test(10  , 4  ) == 2  )
assert(test(10.0, 4.0) == 2.5)

Or you forget about Integral and Fractional and define individual cases:

object StrangeDiv {
  implicit object IntDiv extends StrangeDiv[Int] {
    def strangeDiv(a: Int, b: Int): Int = a / b
  }
  implicit object DoubleDiv extends StrangeDiv[Double] {
    def strangeDiv(a: Double, b: Double): Double = a / b
  }
}
trait StrangeDiv[A] {
  def strangeDiv(a: A, b: A): A
}


标签: scala