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
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
}