Created
June 11, 2015 16:34
-
-
Save octonato/60e492abfcff2e2e7860 to your computer and use it in GitHub Desktop.
Writer/Reader (Shapeless workshop ScalaDays 2015)
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
/* | |
* 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 | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment