Introduction
An important principle of good code design is to avoid repetition and it is known as do not repeat yourself (DRY).
Ad Hoc Polymorphism:
Ad Hoc Polymorphism is utilizing a possibly different implementations based on Types.
Agenda
- Implement Type Class Pattern using Scala.
- Implement Type Class Pattern using Simulacrum.
Code: By Scala
trait Number[T] { def plus(t1: T, t2: T): T def minus(t1: T, t2: T): T def divide(t1: T, t2: Int): T def multiply(t1: T, t2: T): T def sqrt(t1: T): T } object Number { implicit object DoubleNumber extends Number[Double] { override def plus(t1: Double, t2: Double): Double = t1 + t2 override def minus(t1: Double, t2: Double): Double = t1 - t2 override def divide(t1: Double, t2: Int): Double = t1 / t2 override def multiply(t1: Double, t2: Double): Double = t1 * t2 override def sqrt(t1: Double): Double = Math.sqrt(t1) } implicit object IntNumber extends Number[Int] { override def plus(t1: Int, t2: Int): Int = t1 + t2 + 10 override def minus(t1: Int, t2: Int): Int = t1 - t2 override def divide(t1: Int, t2: Int): Int = t1 / t2 override def multiply(t1: Int, t2: Int): Int = t1 * t2 override def sqrt(t1: Int): Int = Math.sqrt(t1).toInt } }
class StatsExample { def mean[T: Number] (xs: Vector[T]): T = implicitly[Number[T]] .divide (xs.reduce(implicitly[Number[T]].plus(_, _)), xs.size) //assume vector is in sorted order def median[T: Number] (xs: Vector[T]): T = xs(xs.size / 2) } object StatsExample extends App { val intVector = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 20, 21, 22, 23, 24, 25) val doubleVector = Vector(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0) val example = new StatsExample println(s"Mean (int) ${example.mean(intVector)}") println(s"Median (int) ${example.median(intVector)}") println(s"Mean (double) ${example.mean(doubleVector)}") println(s"Median (double) ${example.median(doubleVector)}") }
Code: By Simulacrum
@typeclass trait Number[T] { @op("+") def plus(t1: T, t2: T): T @op("-") def minus(t1: T, t2: T): T @op("/") def divide(t1: T, t2: Int): T @op("*") def multiply(t1: T, t2: T): T @op("^") def sqrt(t1: T): T } object Number { implicit object DoubleNumber extends Number[Double] { override def plus(t1: Double, t2: Double): Double = t1 + t2 override def minus(t1: Double, t2: Double): Double = t1 - t2 override def divide(t1: Double, t2: Int): Double = t1 / t2 override def multiply(t1: Double, t2: Double): Double = t1 * t2 override def sqrt(t1: Double): Double = Math.sqrt(t1) } implicit object IntNumber extends Number[Int] { override def plus(t1: Int, t2: Int): Int = t1 + t2 override def minus(t1: Int, t2: Int): Int = t1 - t2 override def divide(t1: Int, t2: Int): Int = t1 / t2 override def multiply(t1: Int, t2: Int): Int = t1 * t2 override def sqrt(t1: Int): Int = Math.sqrt(t1).toInt } }
class StatsExample { import Number.ops._ def mean[T: Number] (xs: Vector[T]): T = xs.reduce(_ + _) / xs.size //assume vector is in sorted order def median[T: Number] (xs: Vector[T]): T = xs(xs.size / 2) } object StatsExample extends App { val intVector = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 20, 21, 22, 23, 24, 25) val doubleVector = Vector(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0) val example = new StatsExample println(s"Mean (int) ${example.mean(intVector)}") println(s"Median (int) ${example.median(intVector)}") println(s"Mean (double) ${example.mean(doubleVector)}") println(s"Median (double) ${example.median(doubleVector)}") }
No comments:
Post a Comment