Skip to content

Instantly share code, notes, and snippets.

@octonato
Created June 11, 2015 16:34
Show Gist options
  • Select an option

  • Save octonato/60e492abfcff2e2e7860 to your computer and use it in GitHub Desktop.

Select an option

Save octonato/60e492abfcff2e2e7860 to your computer and use it in GitHub Desktop.

Revisions

  1. Renato Cavalcanti created this gist Jun 11, 2015.
    802 changes: 802 additions & 0 deletions type-classs-derivation.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,802 @@
    /*
    * Copyright (c) 2015 Miles Sabin
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    * http://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License.
    */

    package derivation

    import shapeless._

    import scala.util.Try

    object repr extends ShowReprDefns {

    sealed trait Animal
    case class Cat(name: String, fish: Int) extends Animal
    case class Dog(name: String, bones: Int) extends Animal

    val felix: Animal = Cat("Felix", 1)
    val tigger: Animal = Dog("Tigger", 2)
    }


    object writer {

    trait Writer[T] {

    def write(t: T): String
    }

    object Writer {

    def write[T](t: T)(implicit writer: Writer[T]): String = {
    writer.write(t)
    }

    implicit val intWriter = new Writer[Int] {
    def write(t: Int): String = s"$t : Int"
    }
    implicit val stringWriter = new Writer[String] {
    def write(t: String): String = s"$t : String"
    }

    implicit val booleanWriter = new Writer[Boolean] {
    def write(t: Boolean): String = s"$t : Boolean"
    }

    // Base case for products
    implicit val writerHNil: Writer[HNil] = new Writer[HNil] {
    def write(t: HNil): String = ""
    }

    // induction for products
    implicit def writerHCons[H, T <: HList](implicit writerH: Lazy[Writer[H]],
    writerT: Lazy[Writer[T]]): Writer[H :: T] =
    new Writer[H :: T] {
    def write(t: H :: T): String =
    writerH.value.write(t.head) + ", " + writerT.value.write(t.tail)
    }

    implicit val writerCNil: Writer[CNil] = new Writer[CNil] {
    def write(t: CNil): String = ""
    }

    implicit def writerCoproduct[H, T <: Coproduct](implicit
    writerH: Lazy[Writer[H]],
    writerT: Lazy[Writer[T]]): Writer[H :+: T] = {
    new Writer[H :+: T] {
    override def write(t: :+:[H, T]): String = t match {
    case Inl(l) => writerH.value.write(l)
    case Inr(r) => writerT.value.write(r)
    }
    }
    }

    implicit def writerGeneric[T, R](implicit gen: Generic.Aux[T, R],
    writerRepr: Lazy[Writer[R]]): Writer[T] = new Writer[T] {
    def write(t: T): String = writerRepr.value.write(gen.to(t))
    }

    implicit class RichAnimal(val animal: Animal) extends AnyVal {

    def write(implicit writer: Writer[Animal]) = writer.write(animal)
    }

    }


    sealed trait Animal

    case class Cat(name: String, fish: Int, badAttitude: Boolean) extends Animal

    case class Dog(name: String, bones: Int) extends Animal

    case class Cow(steak:String) extends Animal

    }

    object reader {

    trait Reader[T] {

    def read(in: String): T
    }

    object Reader {
    def read[T](s: String)(implicit reader: Reader[T]): T = {
    reader.read(s)
    }

    implicit val intReader: Reader[Int] = new Reader[Int] {
    def read(in: String): Int = in.toInt
    }
    implicit val stringReader: Reader[String] = new Reader[String] {
    def read(in: String): String = in
    }
    implicit val booleanReader: Reader[Boolean] = new Reader[Boolean] {
    def read(in: String): Boolean = in.toBoolean
    }
    implicit val hnilReader: Reader[HNil] = new Reader[HNil] {
    def read(in: String): HNil = HNil
    }

    import scala.collection.immutable.{:: => :&:}

    implicit def productReader[H, T <: HList](implicit hReader: Lazy[Reader[H]],
    tReader: Lazy[Reader[T]]): Reader[H :: T] = new Reader[H :: T] {


    def read(in: String): H :: T = {
    val (head :&: tail) = in.split(",").toList

    hReader.value.read(head.takeWhile(_ != ':').trim) :: tReader.value.read(tail.mkString(","))
    }
    }

    implicit val cnilReader: Reader[CNil] = new Reader[CNil] {
    def read(in: String): CNil = null
    }

    implicit def coproductReader[H, T <: Coproduct](implicit
    hReader: Lazy[Reader[H]],
    tReader: Lazy[Reader[T]]): Reader[H:+:T] = new Reader[H:+:T] {
    def read(in: String): H :+: T = {
    Try(Inl[H,T](hReader.value.read(in))).recover {
    case _ => Inr[H,T](tReader.value.read(in))
    }.get
    }
    }

    implicit def readerGeneric[T, R](implicit gen: Generic.Aux[T, R],
    readerRepr: Lazy[Reader[R]]): Reader[T] = new Reader[T] {
    def read(str: String): T = gen.from(readerRepr.value.read(str))
    }

    }

    }

    object equalManual {
    // Cats/Algebra Eq
    trait Eq[T] {
    def eqv(x: T, y: T): Boolean
    }

    object Eq {
    implicit val eqInt: Eq[Int] =
    new Eq[Int] {
    def eqv(x: Int, y: Int): Boolean = x == y
    }

    implicit val eqString: Eq[String] =
    new Eq[String] {
    def eqv(x: String, y: String): Boolean = x == y
    }
    }

    implicit class EqOps[T](x: T)(implicit eqT: Eq[T]) {
    def ===(y: T): Boolean = eqT.eqv(x, y)
    }

    sealed trait Animal
    case class Cat(name: String, fish: Int) extends Animal
    case class Dog(name: String, bones: Int) extends Animal

    object Animal {
    implicit val eqAnimal: Eq[Animal] =
    new Eq[Animal] {
    def eqv(x: Animal, y: Animal): Boolean =
    (x, y) match {
    case (x: Cat, y: Cat) => x === y
    case (x: Dog, y: Dog) => x === y
    case _ => false
    }
    }
    }

    object Cat {
    implicit val eqCat: Eq[Cat] =
    new Eq[Cat] {
    def eqv(x: Cat, y: Cat): Boolean =
    x.name === y.name && x.fish === y.fish
    }
    }

    object Dog {
    implicit val eqDog: Eq[Dog] =
    new Eq[Dog] {
    def eqv(x: Dog, y: Dog): Boolean =
    x.name === y.name && x.bones === y.bones
    }
    }

    val felix: Animal = Cat("Felix", 1)
    val tigger: Animal = Dog("Tigger", 2)
    }

    object equal {
    // Cats/Algebra Eq
    trait Eq[T] {
    def eqv(x: T, y: T): Boolean
    }

    object Eq {
    implicit val eqInt: Eq[Int] =
    new Eq[Int] {
    def eqv(x: Int, y: Int): Boolean = x == y
    }

    implicit val eqString: Eq[String] =
    new Eq[String] {
    def eqv(x: String, y: String): Boolean = x == y
    }

    implicit def eqGeneric[T, R]
    (implicit
    gen: Generic.Aux[T, R],
    eqRepr: Lazy[Eq[R]]
    ): Eq[T] =
    new Eq[T] {
    def eqv(x: T, y: T): Boolean =
    eqRepr.value.eqv(gen.to(x), gen.to(y))
    }

    // Base case for products
    implicit val eqHNil: Eq[HNil] = new Eq[HNil] {
    def eqv(x: HNil, y: HNil): Boolean = true
    }

    // Induction step for products
    implicit def eqHCons[H, T <: HList]
    (implicit
    eqH: Lazy[Eq[H]],
    eqT: Lazy[Eq[T]]
    ): Eq[H :: T] =
    new Eq[H :: T] {
    def eqv(x: H :: T, y: H :: T): Boolean =
    eqH.value.eqv(x.head, y.head) && eqT.value.eqv(x.tail, y.tail)
    }

    // Base case for coproducts
    implicit val eqCNil: Eq[CNil] = new Eq[CNil] {
    def eqv(x: CNil, y: CNil): Boolean = true
    }

    // Induction step for products
    implicit def eqCNCons[H, T <: Coproduct]
    (implicit
    eqH: Lazy[Eq[H]],
    eqT: Lazy[Eq[T]]
    ): Eq[H :+: T] =
    new Eq[H :+: T] {
    def eqv(x: H :+: T, y: H :+: T): Boolean =
    (x, y) match {
    case (Inl(xh), Inl(yh)) => eqH.value.eqv(xh, yh)
    case (Inr(xt), Inr(yt)) => eqT.value.eqv(xt, yt)
    case _ => false
    }
    }
    }

    implicit class EqOps[T](x: T)(implicit eqT: Eq[T]) {
    def ===(y: T): Boolean = eqT.eqv(x, y)
    }

    sealed trait Animal
    case class Cat(name: String, fish: Int) extends Animal
    case class Dog(name: String, bones: Int) extends Animal

    val felix: Animal = Cat("Felix", 1)
    val tigger: Animal = Dog("Tigger", 2)
    }

    object ordering {
    // Cats/Algebra Order
    trait Order[T] {
    def compare(x: T, y: T): Int
    }

    object Order {
    implicit val ordInt: Order[Int] =
    new Order[Int] {
    def compare(x: Int, y: Int): Int = x-y
    }

    implicit val ordString: Order[String] =
    new Order[String] {
    def compare(x: String, y: String): Int = x compare y
    }

    implicit def ordGeneric[T, R]
    (implicit
    gen: Generic.Aux[T, R],
    ordRepr: Lazy[Order[R]]
    ): Order[T] =
    new Order[T] {
    def compare(x: T, y: T): Int =
    ordRepr.value.compare(gen.to(x), gen.to(y))
    }

    // Base case for products
    implicit val ordHNil: Order[HNil] = new Order[HNil] {
    def compare(x: HNil, y: HNil): Int = 0
    }

    // Induction step for products
    implicit def ordHCons[H, T <: HList]
    (implicit
    ordH: Lazy[Order[H]],
    ordT: Lazy[Order[T]]
    ): Order[H :: T] =
    new Order[H :: T] {
    def compare(x: H :: T, y: H :: T): Int = {
    val cmpH = ordH.value.compare(x.head, y.head)
    if(cmpH != 0) cmpH else ordT.value.compare(x.tail, y.tail)
    }
    }

    // Base case for coproducts
    implicit val ordCNil: Order[CNil] = new Order[CNil] {
    def compare(x: CNil, y: CNil): Int = 0
    }

    // Induction step for products
    implicit def ordCNCons[H, T <: Coproduct]
    (implicit
    ordH: Lazy[Order[H]],
    ordT: Lazy[Order[T]]
    ): Order[H :+: T] =
    new Order[H :+: T] {
    def compare(x: H :+: T, y: H :+: T): Int =
    (x, y) match {
    case (Inl(xh), Inl(yh)) => ordH.value.compare(xh, yh)
    case (Inl(xh), Inr(yt)) => 1
    case (Inr(xh), Inl(yt)) => -1
    case (Inr(xt), Inr(yt)) => ordT.value.compare(xt, yt)
    }
    }
    }

    implicit class OrderOps[T](x: T)(implicit ordT: Order[T]) {
    def compare(y: T): Int = ordT.compare(x, y)
    }

    sealed trait Animal
    case class Cat(name: String, fish: Int) extends Animal
    case class Dog(name: String, bones: Int) extends Animal

    val felix: Animal = Cat("Felix", 1)
    val tigger: Animal = Dog("Tigger", 2)
    }

    object monoid {
    // Cats/Algebra monoid
    trait Monoid[T] {
    def empty: T
    def combine(x: T, y: T): T
    }

    object Monoid {
    def apply[T](implicit monT: Monoid[T]) = monT

    implicit val booleanMonoid: Monoid[Boolean] =
    new Monoid[Boolean] {
    val empty = false
    def combine(x: Boolean, y: Boolean) = x || y
    }

    implicit val intMonoid: Monoid[Int] =
    new Monoid[Int] {
    val empty = 0
    def combine(x: Int, y: Int) = x+y
    }

    implicit val doubleMonoid: Monoid[Double] =
    new Monoid[Double] {
    val empty = 0.0
    def combine(x: Double, y: Double) = x+y
    }

    implicit val stringMonoid: Monoid[String] =
    new Monoid[String] {
    val empty = ""
    def combine(x: String, y: String) = x+y
    }

    implicit def monGeneric[T, R]
    (implicit
    gen: Generic.Aux[T, R],
    monRepr: Lazy[Monoid[R]]
    ): Monoid[T] =
    new Monoid[T] {
    val empty = gen.from(monRepr.value.empty)
    def combine(x: T, y: T): T =
    gen.from(monRepr.value.combine(gen.to(x), gen.to(y)))
    }

    // Base case for products
    implicit val monHNil: Monoid[HNil] = new Monoid[HNil] {
    val empty = HNil
    def combine(x: HNil, y: HNil) = HNil
    }

    // Induction step for products
    implicit def monHCons[H, T <: HList]
    (implicit
    monH: Lazy[Monoid[H]],
    monT: Lazy[Monoid[T]]
    ): Monoid[H :: T] =
    new Monoid[H :: T] {
    val empty = monH.value.empty :: monT.value.empty
    def combine(x: H :: T, y: H :: T) =
    monH.value.combine(x.head, y.head) ::
    monT.value.combine(x.tail, y.tail)
    }
    }

    implicit class MonoidOps[T](x: T)(implicit monT: Monoid[T]) {
    def combine(y: T): T = monT.combine(x, y)
    }

    case class Cat(name: String, fish: Int)
    case class Dog(name: String, bones: Int)

    val felix = Cat("Felix", 1)
    val tigger = Dog("Tigger", 2)
    }

    object show {
    // Show using low-level infrastructure ...

    import labelled._

    trait Show[T] {
    def show(t: T): String
    }

    object Show {
    implicit val showString: Show[String] = new Show[String] {
    def show(t: String) = t
    }

    implicit val showInt: Show[Int] = new Show[Int] {
    def show(t: Int) = t.toString
    }

    implicit def showList[A](implicit showA: Show[A]): Show[List[A]] = new Show[List[A]] {
    def show(t: List[A]) = t.map(showA.show).mkString("List(", ", ", ")")
    }

    implicit def showGeneric[F, G](implicit gen: LabelledGeneric.Aux[F, G], sg: Lazy[Show[G]]): Show[F] =
    new Show[F] {
    def show(f: F) = sg.value.show(gen.to(f))
    }

    implicit def showHNil: Show[HNil] =
    new Show[HNil] {
    def show(p: HNil): String = ""
    }

    implicit def showHCons[K <: Symbol, V, T <: HList]
    (implicit
    key: Witness.Aux[K],
    sv: Lazy[Show[V]],
    st: Lazy[Show[T]]
    ): Show[FieldType[K, V] :: T] =
    new Show[FieldType[K, V] :: T] {
    def show(p: FieldType[K, V] :: T): String = {
    val head = s"${key.value.name} = ${sv.value.show(p.head)}"
    val tail = st.value.show(p.tail)
    if(tail.isEmpty) head else s"$head, $tail"
    }
    }

    implicit def showCNil: Show[CNil] =
    new Show[CNil] {
    def show(p: CNil): String = ""
    }

    implicit def showCCons[K <: Symbol, V, T <: Coproduct]
    (implicit
    key: Witness.Aux[K],
    sv: Lazy[Show[V]],
    st: Lazy[Show[T]]
    ): Show[FieldType[K, V] :+: T] =
    new Show[FieldType[K, V] :+: T] {
    def show(c: FieldType[K, V] :+: T): String =
    c match {
    case Inl(l) => s"${key.value.name}(${sv.value.show(l)})"
    case Inr(r) => st.value.show(r)
    }
    }
    }

    implicit class ShowOps[T](x: T)(implicit showT: Show[T]) {
    def show: String = showT.show(x)
    }

    sealed trait Animal
    case class Cat(name: String, fish: Int) extends Animal
    case class Dog(name: String, bones: Int) extends Animal

    val felix = Cat("Felix", 1)
    val tigger = Dog("Tigger", 2)
    }

    object show2 {
    // Show using TypeClass
    trait Show[T] {
    def show(t: T): String
    }

    object Show extends LabelledTypeClassCompanion[Show] {
    implicit def stringShow: Show[String] = new Show[String] {
    def show(t: String) = t
    }

    implicit def intShow: Show[Int] = new Show[Int] {
    def show(n: Int) = n.toString
    }

    object typeClass extends LabelledTypeClass[Show] {
    def emptyProduct = new Show[HNil] {
    def show(t: HNil) = ""
    }

    def product[F, T <: HList](name: String, sh: Show[F], st: Show[T]) = new Show[F :: T] {
    def show(ft: F :: T) = {
    val head = sh.show(ft.head)
    val tail = st.show(ft.tail)
    if (tail.isEmpty)
    s"$name = $head"
    else
    s"$name = $head, $tail"
    }
    }

    def emptyCoproduct = new Show[CNil] {
    def show(t: CNil) = ""
    }

    def coproduct[L, R <: Coproduct](name: String, sl: => Show[L], sr: => Show[R]) = new Show[L :+: R] {
    def show(lr: L :+: R) = lr match {
    case Inl(l) => s"$name(${sl.show(l)})"
    case Inr(r) => s"${sr.show(r)}"
    }
    }

    def project[F, G](instance: => Show[G], to: F => G, from: G => F) = new Show[F] {
    def show(f: F) = instance.show(to(f))
    }
    }
    }

    implicit class ShowOps[T](x: T)(implicit showT: Show[T]) {
    def show: String = showT.show(x)
    }

    sealed trait Animal
    case class Cat(name: String, fish: Int) extends Animal
    case class Dog(name: String, bones: Int) extends Animal

    val felix = Cat("Felix", 1)
    val tigger = Dog("Tigger", 2)
    }

    object functor {
    trait Functor[F[_]] {
    def map[A, B](fa: F[A])(f: A => B): F[B]
    }

    object Functor extends Functor0 {
    def apply[F[_]](implicit f: Lazy[Functor[F]]): Functor[F] = f.value

    implicit val idFunctor: Functor[Id] =
    new Functor[Id] {
    def map[A, B](a: A)(f: A => B): B = f(a)
    }

    // Induction step for products
    implicit def hcons[F[_]](implicit ihc: IsHCons1[F, Functor, Functor]): Functor[F] =
    new Functor[F] {
    def map[A, B](fa: F[A])(f: A => B): F[B] = {
    val (hd, tl) = ihc.unpack(fa)
    ihc.pack((ihc.fh.map(hd)(f), ihc.ft.map(tl)(f)))
    }
    }

    // Induction step for coproducts
    implicit def ccons[F[_]](implicit icc: IsCCons1[F, Functor, Functor]): Functor[F] =
    new Functor[F] {
    def map[A, B](fa: F[A])(f: A => B): F[B] =
    icc.pack(icc.unpack(fa).fold(hd => Left(icc.fh.map(hd)(f)), tl => Right(icc.ft.map(tl)(f))))
    }

    implicit def generic[F[_]](implicit gen: Generic1[F, Functor]): Functor[F] =
    new Functor[F] {
    def map[A, B](fa: F[A])(f: A => B): F[B] =
    gen.from(gen.fr.map(gen.to(fa))(f))
    }
    }

    trait Functor0 {
    implicit def constFunctor[T]: Functor[Const[T]#λ] =
    new Functor[Const[T]#λ] {
    def map[A, B](t: T)(f: A => B): T = t
    }
    }

    implicit class FunctorOps[F[_], A](fa: F[A])(implicit F: Functor[F]) {
    def map[B](f: A => B): F[B] = F.map(fa)(f)
    }

    sealed trait Tree[T]
    case class Leaf[T](t: T) extends Tree[T]
    case class Node[T](l: Tree[T], r: Tree[T]) extends Tree[T]

    val tree =
    Node(
    Leaf("quux"),
    Node(
    Leaf("foo"),
    Leaf("wibble")
    )
    )
    }

    object foldable {
    import scala.util.control.TailCalls._

    trait Foldable[F[_]] {
    def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B): B
    }

    object Foldable {
    implicit def apply[F[_]](implicit fr: Lazy[FoldableRec[F]]): Foldable[F] =
    new Foldable[F] {
    def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B): B = fr.value.foldLeft(fa, b)(f).result
    }
    }

    trait FoldableRec[F[_]] {
    def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B): TailRec[B]
    }

    object FoldableRec extends FoldableRec0 {
    def apply[F[_]](implicit F: Lazy[FoldableRec[F]]): FoldableRec[F] = F.value

    implicit val idFoldableRec: FoldableRec[Id] =
    new FoldableRec[Id] {
    def foldLeft[A, B](fa: A, b: B)(f: (B, A) => B) =
    done(f(b, fa))
    }

    implicit def hcons[F[_]](implicit F: IsHCons1[F, FoldableRec, FoldableRec]): FoldableRec[F] =
    new FoldableRec[F] {
    override def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B) = {
    val (hd, tl) = F.unpack(fa)
    for {
    h <- F.fh.foldLeft(hd, b)(f)
    t <- F.ft.foldLeft(tl, h)(f)
    } yield t
    }
    }

    implicit def ccons[F[_]](implicit F: IsCCons1[F, FoldableRec, FoldableRec]): FoldableRec[F] =
    new FoldableRec[F] {
    def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B) =
    F.unpack(fa) match {
    case Left(l) =>
    tailcall(F.fh.foldLeft(l, b)(f))
    case Right(r) =>
    tailcall(F.ft.foldLeft(r, b)(f))
    }
    }

    implicit def generic[F[_]](implicit F: Generic1[F, FoldableRec]): FoldableRec[F] =
    new FoldableRec[F] {
    def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B) =
    tailcall(F.fr.foldLeft(F.to(fa), b)(f))
    }
    }

    sealed abstract class FoldableRec0 {
    implicit def constFoldableRec[T]: FoldableRec[Const[T]#λ] =
    new FoldableRec[Const[T]#λ] {
    override def foldLeft[A, B](fa: T, b: B)(f: (B, A) => B) =
    done(b)
    }
    }

    implicit class FoldableOps[F[_], A](fa: F[A])(implicit F: Foldable[F]) {
    def foldLeft[B](b: B)(f: (B, A) => B): B = F.foldLeft(fa, b)(f)
    }

    sealed trait Tree[T]
    case class Leaf[T](t: T) extends Tree[T]
    case class Node[T](l: Tree[T], r: Tree[T]) extends Tree[T]

    val tree =
    Node(
    Leaf("quux"),
    Node(
    Leaf("foo"),
    Leaf("wibble")
    )
    )

    sealed abstract class IList[A]
    final case class ICons[A](head: A, tail: IList[A]) extends IList[A]
    final case class INil[A]() extends IList[A]

    val list = (1 to 100000).foldLeft(ICons(0, INil())){ (acc, i) => ICons(i, acc) }
    }

    trait ShowReprDefns {
    def showRepr[T](t: T)(implicit st: ShowRepr[T]): String = st(t)

    trait ShowRepr[T] {
    def apply(t: T): String
    }

    object ShowRepr extends ShowRepr0 {
    implicit val hnilShowRepr: ShowRepr[HNil] =
    new ShowRepr[HNil] {
    def apply(t: HNil): String = "HNil"
    }

    implicit def hconsShowRepr[H, T <: HList]
    (implicit
    sh: Lazy[ShowRepr[H]],
    st: Lazy[ShowRepr[T]]
    ): ShowRepr[H :: T] =
    new ShowRepr[H :: T] {
    def apply(t: H :: T): String = sh.value(t.head)+" :: "+st.value(t.tail)
    }

    implicit val cnilShowRepr: ShowRepr[CNil] =
    new ShowRepr[CNil] {
    def apply(t: CNil): String = "CNil"
    }

    implicit def cconsShowRepr[H, T <: Coproduct]
    (implicit
    sh: Lazy[ShowRepr[H]],
    st: Lazy[ShowRepr[T]]
    ): ShowRepr[H :+: T] =
    new ShowRepr[H :+: T] {
    def apply(t: H :+: T): String =
    t match {
    case Inl(l) => "Inl("+sh.value(l)+")"
    case Inr(r) => "Inr("+st.value(r)+")"
    }
    }

    implicit def genShowRepr[T, R]
    (implicit
    gen: Generic.Aux[T, R],
    sr: Lazy[ShowRepr[R]]
    ): ShowRepr[T] =
    new ShowRepr[T] {
    def apply(t: T): String = sr.value(gen.to(t))
    }
    }

    trait ShowRepr0 {
    implicit def default[T]: ShowRepr[T] =
    new ShowRepr[T] {
    def apply(t: T): String = t.toString
    }
    }
    }