Skip to content

Instantly share code, notes, and snippets.

@lshoo
Created September 13, 2017 10:07
Show Gist options
  • Save lshoo/ff75a2fc890f72eb730dbed03902c41c to your computer and use it in GitHub Desktop.
Save lshoo/ff75a2fc890f72eb730dbed03902c41c to your computer and use it in GitHub Desktop.
Shapeless example
import shapeless.{:+:, ::, CNil, Coproduct, Generic, HList, HNil, Inl, Inr, Lazy}
/**
* http://www.cakesolutions.net/teamblogs/solving-problems-in-a-generic-way-using-shapeless
*/
trait Depth[T] {
def depth(t: T): Int
}
object Depth {
def createDepth[A](func: A => Int): Depth[A] = new Depth[A] {
override def depth(t: A): Int = func(t)
}
implicit def stringDepth: Depth[String] = createDepth { str => 1 }
implicit def intDepth: Depth[Int] = createDepth(_ => 1)
implicit def listDepth[A](implicit elementDepth: Depth[A]): Depth[List[A]] = createDepth { list =>
if (list.isEmpty) 1 else list.map(elementDepth.depth).max + 1
}
implicit val hnilDepth: Depth[HNil] = createDepth(_ => 0)
implicit def hlistDepth[H, T <: HList](implicit hDepth: Lazy[Depth[H]], tDepth: Depth[T]): Depth[H :: T] = createDepth {
case h :: t =>
(hDepth.value.depth(h) + 1) max tDepth.depth(t)
}
implicit val cnilDepth: Depth[CNil] = createDepth(_ => 0)
implicit def coproductDepth[H, T <: Coproduct](
implicit
hDepth: Depth[H],
tDepth: Depth[T]
): Depth[H :+: T] = createDepth {
case Inl(h) =>
hDepth.depth(h)
case Inr(t) =>
tDepth.depth(t)
}
implicit def genericDepth[A, H <: HList](implicit gen: Lazy[Generic.Aux[A, H]], depth: Depth[H]): Depth[A] = createDepth { a =>
depth.depth(gen.value.to(a))
}
}
object DepthApp {
case class Coordinate(x: Int, y: Int)
sealed trait Shape
case class Circle(radius: Int, center: Coordinate) extends Shape
case class Rectangle(corner1: Coordinate, corner2: Coordinate) extends Shape
case class Triangle(corner1: Coordinate, corner2: Coordinate, corner3: Coordinate) extends Shape
case class Surface(name: String, shape1: Shape, shape2: Shape)
def depth[A](value: A)(implicit depth: Depth[A]): Int = depth.depth(value)
def main(args: Array[String]): Unit = {
import Depth._
val c1 = Coordinate(1, 2)
val c2 = Coordinate(3, 4)
val c3 = Coordinate(5, 6)
val c4 = Coordinate(7, 8)
val circle1 = Circle(2, c1)
val rectangle1 = Rectangle(c2, c3)
val triangle1 = Triangle(c1, c2, c3)
val surface1 = Surface("surface1", circle1, rectangle1)
println(s"Coordinate depth: ${depth(c1)}")
println(s"Circle depth: ${depth(circle1)}")
println(s"Rectangle1 depth: ${depth(rectangle1)}")
println(s"Triangle1 depth: ${depth(triangle1)}")
println(s"Surface1 depth: ${depth(surface1)}")
}
@lshoo
Copy link
Author

lshoo commented Sep 14, 2017

The genericDepth is wrong, thanks @diff
The right is
implicit def genericDepth[A, H](implicit gen: Generic.Aux[A, H], depth: Lazy[Depth[H]]): Depth[A] = createDepth { a =>
depth.value.depth(gen.to(a))
}

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