trait L case class C(hd: Int, tl: L) extends L case object N extends L trait Sum[+S1, +S2] case class Fst[+F](x: F) extends Sum[F, Nothing] case class Snd[+S](x: S) extends Sum[Nothing, S] case class Prod[+P1, +P2](fst: P1, snd: P2) trait shaped[SH1, SH2] { def toShape(x: SH1): SH2 def fromShape(x: SH2): SH1 } object Test { type LShape = Sum[Prod[Int, L], Unit] implicit def LShape: L `shaped` LShape = new (L `shaped` LShape) { def toShape(xs: L) = xs match { case C(x, xs1) => Fst(Prod(x, xs1)) case N => Snd(()) } def fromShape(sh: LShape) = sh match { case Fst(Prod(x, xs1)) => C(x, xs1) case Snd(()) => N } } trait Listable[T] { def toList(x: T): List[Int] } implicit def ShapedListable[T, U](implicit ev1: T shaped U, ev2: Listable[U] ): Listable[T] = new Listable[T] { def toList(x: T) = ev2.toList(ev1.toShape(x)) } implicit def SumListable[T, U](implicit ev1: => Listable[T], ev2: => Listable[U] ): Listable[Sum[T, U]] = new Listable[Sum[T, U]] { def toList(s: Sum[T, U]) = s match { case Fst(x) => ev1.toList(x) case Snd(x) => ev2.toList(x) } } implicit def ProdListable[T, U](implicit ev1: Listable[T], ev2: Listable[U] ): Listable[Prod[T, U]] = new Listable[Prod[T, U]] { def toList(p: Prod[T, U]) = ev1.toList(p.fst) ++ ev2.toList(p.snd) } implicit def IntListable: Listable[Int] = new Listable[Int] { def toList(n: Int) = n :: Nil } implicit def UnitListable: Listable[Unit] = new Listable[Unit] { def toList(u: Unit) = Nil } def toList[T, U >: T](x: T)(implicit ev1: Listable[U]) = ev1.toList(x) def main(args: Array[String]) = { locally { // with specialized Listable implicit lazy val LListable: Listable[L] = ShapedListable println(toList(N)) println(toList(C(1, C(2, C(3, N))))) } locally { // without specialized Listable println(toList(N)) println(toList(C(1, C(2, C(3, N))))) } } }