Skip to content

Instantly share code, notes, and snippets.

@ryanlecompte
Last active September 9, 2019 01:31
Show Gist options
  • Save ryanlecompte/ec2d9f9e23e09c08903c to your computer and use it in GitHub Desktop.
Save ryanlecompte/ec2d9f9e23e09c08903c to your computer and use it in GitHub Desktop.
Magnet/Typeclass pattern example
// Magnet pattern documented here: http://spray.io/blog/2012-12-13-the-magnet-pattern/
object TypeclassExample {
// first, define the typeclass
trait Plotter[A] {
def plot: Unit
}
// this typeclass instance knows how to plot collections
class IterablePlotter[A: Numeric](it: Iterable[A]) extends Plotter[Iterable[A]] {
def plot: Unit = println(s"plotting collection: $it")
}
// this typeclass instance knows how to plot functions
class FunctionPlotter[A: Numeric, B: Numeric](f: A => B) extends Plotter[A => B] {
def plot: Unit = {
val numeric = implicitly[Numeric[A]]
println(s"plotting function: ${f(numeric.fromInt(100))}")
}
}
// next, we define lower priority implicits in a trait so
// that the compiler only uses it as a fallback
trait LowerPriorityImplicits {
implicit def mkFunctionPlotter[A: Numeric, B: Numeric](f: A => B): Plotter[A => B] = new FunctionPlotter(f)
}
// we define our implicit conversion methods here so that
// the compiler can find them appropriately
object Plotter extends LowerPriorityImplicits {
implicit def mkIterablePlotter[A: Numeric](xs: Iterable[A]): Plotter[Iterable[A]] = new IterablePlotter(xs)
}
// our public API
def plot[A](plotter: Plotter[A]): Unit = plotter.plot
}
// ------------------
import TypeclassExample._
// plot some collections
println("plotting collections:")
plot(Iterable(1,2,3))
plot(List(1,2,3))
plot(Set(1,2,3))
plot(Vector(1,2,3))
// plot some functions
println("plotting functions:")
plot { x: Int => x * 2 }
plot(math.sqrt _)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment