|
| 1 | +import language.experimental.modularity |
| 2 | + |
| 3 | +// First version: higher-kinded self type |
| 4 | +object v1: |
| 5 | + trait Sets: |
| 6 | + type Self[A] |
| 7 | + def empty[A]: Self[A] |
| 8 | + def union[A](self: Self[A], other: Self[A]): Self[A] |
| 9 | + |
| 10 | + case class ListSet[A](elems: List[A]) |
| 11 | + |
| 12 | + given ListSet forms Sets: |
| 13 | + def empty[A]: ListSet[A] = ListSet(Nil) |
| 14 | + |
| 15 | + def union[A](self: ListSet[A], other: ListSet[A]): ListSet[A] = |
| 16 | + ListSet(self.elems ++ other.elems) |
| 17 | + |
| 18 | + def listUnion[A, S[_]: Sets](xs: List[S[A]]): S[A] = |
| 19 | + xs.foldLeft(S.empty)(S.union) |
| 20 | + |
| 21 | + val xs = ListSet(List(1, 2, 3)) |
| 22 | + val ys = ListSet(List(4, 5)) |
| 23 | + val zs = listUnion(List(xs, ys)) |
| 24 | + |
| 25 | + // Second version: parameterized type class |
| 26 | +object v2: |
| 27 | + trait Sets[A]: |
| 28 | + type Self |
| 29 | + def empty: Self |
| 30 | + extension (s: Self) def union (other: Self): Self |
| 31 | + |
| 32 | + case class ListSet[A](elems: List[A]) |
| 33 | + |
| 34 | + given [A] => ListSet[A] forms Sets[A]: |
| 35 | + def empty: ListSet[A] = ListSet(Nil) |
| 36 | + |
| 37 | + extension (self: ListSet[A]) def union(other: ListSet[A]): ListSet[A] = |
| 38 | + ListSet(self.elems ++ other.elems) |
| 39 | + |
| 40 | + def listUnion[A, S: Sets[A]](xs: List[S]): S = |
| 41 | + xs.foldLeft(S.empty)(_ `union` _) |
| 42 | + |
| 43 | + val xs = ListSet(List(1, 2, 3)) |
| 44 | + val ys = ListSet(List(4, 5)) |
| 45 | + val zs = listUnion(List(xs, ys)) |
| 46 | + |
0 commit comments