Skip to content

Commit 9e3d234

Browse files
committed
A blue sky sketch how one could possibly evolve extends clauses
1 parent 3b50e39 commit 9e3d234

File tree

1 file changed

+122
-0
lines changed

1 file changed

+122
-0
lines changed
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/** A blue sky sketch how one might evolve extensions to do type classes
2+
* without the current gap between functional and OO patterns.
3+
* Largely inspired by the way Rust does it.
4+
*
5+
* The main additions (to be worked out in detail) is a self type `This` and
6+
* a mechanism that a trait can abstract over companions of classes that implement it.
7+
* Companion types and methods are declared using `static` for now, just to
8+
* pick some familiar notation.
9+
*
10+
* Ideas about `This` (still vague at the moment)
11+
*
12+
* - Treat it as an additional abstract type in a trait, prefixed by the name of the trait
13+
* - An implementing (non-trait) class binds the `This` types of all the traits it implements
14+
* to itself.
15+
* - Later subclasses do not re-bind `This` types already bound by their superclasses.
16+
* (so in that sense, `This`-binding is like trait parameterization, the first implementing
17+
* classes determines the self type and the parameters of a trait)
18+
* - Paramerized classes have parameterized `This` types (e.g. Functor below).
19+
*/
20+
import Predef.{any2stringadd => _, _}
21+
object blueSkyExtensions {
22+
23+
// Semigroup and Monoid
24+
25+
trait SemiGroup {
26+
def + (that: This): This
27+
}
28+
29+
trait Monoid extends SemiGroup {
30+
static def unit: This
31+
}
32+
33+
extend Int : Monoid {
34+
def + (that: Int) = this + that
35+
static def unit = 0
36+
}
37+
38+
extend String : Monoid {
39+
def + (that: Int) = this ++ that
40+
static def unit = ""
41+
}
42+
43+
// Ord
44+
45+
trait Ord {
46+
def compareTo(that: This): Int
47+
def < (that: This) = compareTo < 0
48+
def > (that: This) = compareTo > 0
49+
}
50+
51+
extend List[type T : Ord] : Ord {
52+
def compareTo(that: List[T]): Int = (this, that) match {
53+
case (Nil, Nil) => 0
54+
case (Nil, _) => -1
55+
case (_, Nil) => +1
56+
case (x :: xs, y :: ys) =>
57+
val fst = x.compareTo(y)
58+
if (fst != 0) fst else xs.compareTo(ys)
59+
}
60+
}
61+
62+
// Functor and Monad
63+
64+
trait Functor[A] {
65+
static def pure[A]: This[A]
66+
67+
def map[B](f: A => B): This[B]
68+
}
69+
70+
trait Monad[A] extends Functor[A] {
71+
static def pure[A]: This[A]
72+
73+
def flatMap[B](f: A => This[B]): This[B]
74+
def map[B](f: A => B) = this.flatMap(f.andThen(pure))
75+
}
76+
77+
extend List[type T] : Monad[T] {
78+
static def pure[A] = Nil
79+
80+
def flatMap[B](f: A => List[B]): List[B] = this match {
81+
case x :: xs => f(x) ++ xs.flatMap(f)
82+
case Nil => Nil
83+
}
84+
}
85+
86+
extend (type T[X]: Monad[X])[T[type A]] {
87+
def flatten: T[A] = this.flatMap(identity)
88+
}
89+
90+
// Iterables
91+
92+
trait MonoIterable[A] {
93+
def filter(p: A => Boolean): This[A]
94+
static def empty: This[A]
95+
static def apply(xs: A*): This[A]
96+
}
97+
98+
99+
trait Iterable[A] extends MonoIterable[A] {
100+
def map[B](f: A => B): This[B]
101+
def flatMap[B](f: A => This[B]): This[B]
102+
}
103+
104+
extend String : MonoIterable[Char] {
105+
def filter(p: Char => Boolean): String = ...
106+
def map(f: Char => Char): String = ...
107+
static def empty = ""
108+
static def apply(xs: A*) = xs.mkString
109+
}
110+
111+
extend String : Iterable[Char] {
112+
def map[B](f: Char => B): IndexedSeq[B] = ...
113+
def flatMap[B](f: Char => IndexedSeq[B]): IndexedSeq[B] = ...
114+
}
115+
116+
extend List[type T] : Iterable[T] {
117+
def filter(p: T => Boolean): List[T] = ...
118+
def map[B](f: T => B): List[B] = ...
119+
def flatMap[B](f: T => List[B]): List[B] = ...
120+
}
121+
122+
}

0 commit comments

Comments
 (0)