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