aboutsummaryrefslogtreecommitdiff
path: root/tests/run/generic/List.scala
blob: bc01ce63fc14dc58c2a6acbf2cd7b7b59a0041fc (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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
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
      }
    }
}