Skip to content

Instantly share code, notes, and snippets.

@malcolmgreaves
Last active February 23, 2018 04:20
Show Gist options
  • Save malcolmgreaves/df040cb98a52d635fc92a4a4aad437ca to your computer and use it in GitHub Desktop.
Save malcolmgreaves/df040cb98a52d635fc92a4a4aad437ca to your computer and use it in GitHub Desktop.
Generic maximum function (max) with float-value-transforming typeclass (Val).
case class Scored[T](item: T, value: Double)
trait Val[-A] {
def valueOf(a: A): Double
}
object Val {
def apply[T: Val]: Val[T] =
implicitly[Val[T]]
object Implementations {
// simple primitive type implementations
implicit object IntV extends Val[Int] { def valueOf(a: Int) = a.toDouble }
implicit object LongV extends Val[Long] { def valueOf(a: Long) = a.toDouble }
implicit object DoubleV extends Val[Double] { def valueOf(a: Double) = a }
implicit object FloatV extends Val[Float] { def valueOf(a: Float) = a.toDouble }
/** Produce a Val instance for any tuple whose left element has a Val instance in implicit scope. */
implicit def tupleLeftV[T: Val, Anything] = new Val[(T, Anything)] {
def valueOf(a: (T, Anything)) = a match {
case (v, _) => Val[T].valueOf(v)
}
}
/** Produce a Val instance for any tuple whose right element has a Val instance in implicit scope. */
implicit def tupleRightV[Anything, T: Val] = new Val[(Anything, T)] {
def valueOf(a: (Anything, T)) = a match {
case (_, v) => Val[T].valueOf(v)
}
}
implicit def scoredV[Anything]: Val[Scored[Anything]] = new Val[Scored[Anything]] {
def valueOf(a: Scored[Anything]) = a.value
}
}
}
def max[B: Val](xs: Traversable[B]): B =
if (xs.isEmpty)
throw new IllegalArgumentException("Cannot calculate maximum from no input.")
else if (xs.size == 1)
xs.head
else {
xs.slice(1, xs.size).foldLeft(xs.head) {
case (m, next) =>
if (Val[B].valueOf(next) > Val[B].valueOf(m))
next
else
m
}
}
def max_o[B: Val](xs: Traversable[B]): Option[B] =
try {
Some(max(xs))
} catch {
case _: IllegalArgumentException => None
}
def example(): Unit = {
println(max(Seq(1,2,3,4,5))(Val.Implementations.IntV)) // 5
println(max_o(Seq(1,2,3,4,5))(Val.Implementations.IntV)) // Some(5)
println(max(Seq(10.0, 40.0, -1.0, 22.0))(Val.Implementations.DoubleV)) // 40.0
println(max_o(Seq.empty[Long])(Val.Implementations.LongV)) // None
println("-----------------------------------")
import Val.Implementations._
println(max(Seq(1,2,3,4,5))) // 5
println(max_o(Seq(1,2,3,4,5))) // Some(5)
println(max(Seq(10.0, 40.0, -1.0, 22.0))) // 40.0
println(max_o(Seq.empty[Long])) // None
println("-----------------------------------")
println(max(Seq(("hello", 10), ("world", 20)))) // ("world",20)
println(max(Seq((33, "pad thai"), (-1, "universe")))) // (33,"pad thai")
println(max(Seq(Scored("scala",9999.0), Scored("js", 0.0)))) // Scored("scala",9999.0)
}
@carsonkahn-external
Copy link

This is so beautiful I almost cried

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment