aboutsummaryrefslogblamecommitdiff
path: root/tests/run/lazy-implicit-lists.scala
blob: 72099d0b2d07450e59ee3f8b556b5d41f16969d2 (plain) (tree)






















































































                                                                        
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)))))
    }
  }
}