package generic import Shapes._ /** enum List[T] { * case Cons(x: T, xs: List[T]) * case Nil() * } */ sealed trait List0[T] extends Enum object List0 { abstract case class Cons[T](hd: T, tl: List0[T]) extends List0[T] { def enumTag = 0 } object Cons { def apply[T](x: T, xs: List0[T]): List0[T] = new Cons(x, xs) {} implicit def ConsShape[T]: Cons[T] `shaped` Prod[T, List0[T]] = new (Cons[T] `shaped` Prod[T, List0[T]]) { def toShape(x: Cons[T]) = Prod(x.hd, x.tl) def fromShape(p: Prod[T, List0[T]]) = new Cons(p.fst, p.snd) {} } } abstract case class Nil[T]() extends List0[T] { def enumTag = 1 } object Nil { def apply[T](): List0[T] = new Nil[T]() {} implicit def NilShape[T]: Nil[T] `shaped` Unit = new (Nil[T] `shaped` Unit) { def toShape(x: Nil[T]) = () def fromShape(x: Unit) = new Nil[T]() {} } } implicit def List0Shape[T]: List0[T] `shaped` Sum[Cons[T], Nil[T]] = new (List0[T] `shaped` Sum[Cons[T], Nil[T]]) { def toShape(x: List0[T]) = x match { case x: Cons[T] => Fst(x) case x: Nil[T] => Snd(x) } def fromShape(x: Sum[Cons[T], Nil[T]]) = x match { case Fst(c) => c case Snd(n) => n } } } /** enum List[+T] { * case Cons(x: T, xs: List[T]) * case Nil extends List[Nothing] * } */ sealed trait List[+T] extends Enum object List { abstract case class Cons[T](hd: T, tl: List[T]) extends List[T] { def enumTag = 0 } object Cons { def apply[T](x: T, xs: List[T]): List[T] = new Cons(x, xs) {} type Shape[T] = Prod[T, List[T]] implicit def ConsShape[T]: Cons[T] `shaped` Shape[T] = new (Cons[T] `shaped` Shape[T]) { def toShape(x: Cons[T]) = Prod(x.hd, x.tl) def fromShape(p: Shape[T]) = new Cons(p.fst, p.snd) {} } } val Nil = new List[Nothing] { def enumTag = 1 override def toString = "Nil" } implicit def NilSingleton: Singleton[Nil.type] = new Singleton[Nil.type](Nil) type Shape[T] = Sum[Cons[T], Nil.type] implicit def ListShape[T]: List[T] `unfolds` Shape[T] = new (List[T] `shaped` Shape[T]) { def toShape(x: List[T]) = x match { case x: Cons[T] => Fst(x) case Nil => Snd(Nil) } def fromShape(x: Shape[T]): List[T] = x match { case Fst(c) => c case Snd(n) => n } } }