aboutsummaryrefslogtreecommitdiff
path: root/tests/run/lazy-implicit-nums.scala
blob: 967472735eb66156b4b06c0c4b8e1bc0cd354c4f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
trait Nat
case class S(x: Nat) extends Nat
case class Z() extends Nat

trait Sum[+S1, +S2]
case class Fst[+F](x: F) extends Sum[F, Nothing]
case class Snd[+S](x: S) extends Sum[Nothing, S]

trait shaped[SH1, SH2] {
  def toShape(x: SH1): SH2
  def fromShape(x: SH2): SH1
}

object Test {

  type NatShape = Sum[Nat, Z]

  implicit def natShape: Nat `shaped` NatShape =
    new (Nat `shaped` NatShape) {
      def toShape(n: Nat) = n match {
        case S(m) => Fst(m)
        case Z() => Snd(Z())
      }
      def fromShape(s: NatShape) = s match {
        case Fst(n) => S(n)
        case Snd(_) => Z()
      }
    }

  trait Countable[T] {
    def count(x: T): Int
  }

  implicit def ShapedCountable[T, U](implicit
    ev1: T shaped U,
    ev2: Countable[U]
  ): Countable[T] =
    new Countable[T] {
      def count(x: T) = ev2.count(ev1.toShape(x))
    }

  implicit def SumCountable[T, U](implicit
    ev1: => Countable[T]
  ): Countable[Sum[T, U]] =
    new Countable[Sum[T, U]] {
      def count(s: Sum[T, U]) = s match {
        case Fst(x) => ev1.count(x) + 1
        case Snd(_) => 0
      }
    }

  def count[T, U >: T](x: T)(implicit ev1: Countable[U]) = ev1.count(x)

  def main(args: Array[String]) = {
    println(
      count(S(S(S(Z())))))
  }
}