Created
September 13, 2017 10:07
-
-
Save lshoo/ff75a2fc890f72eb730dbed03902c41c to your computer and use it in GitHub Desktop.
Shapeless example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)}") | |
} |
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
when compile the code, will report error:
could not find implicit value for parameter depth:Depth[DepthApp.Surface]
if I comment """println(s"Surface1 depth: ${depth(surface1)}")""", it works.
I think the genericDepth method is wrong.
What is the right define?