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 `object` 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 add (that : This ): This
27
+ }
28
+
29
+ trait Monoid extends SemiGroup {
30
+ static def unit : This
31
+ }
32
+
33
+ extend Int : Monoid {
34
+ def add (that : Int ) = this + that
35
+ static def unit = 0
36
+ }
37
+
38
+ extend String : Monoid {
39
+ def add (that : Int ) = this ++ that
40
+ static def unit = " "
41
+ }
42
+
43
+ def sum [T : Monoid ](xs : List [T ]): T =
44
+ (instance[T , Monoid ].unit /: xs)(_ `add` _)
45
+
46
+ // --->
47
+ {
48
+ trait TypeClass {
49
+ type This
50
+ type Static [This ]
51
+ }
52
+
53
+ trait Implementation [From , To <: TypeClass ] {
54
+ type This = From
55
+ def statics : To # Static [From ]
56
+ def inject (x : From ): To { type This = From }
57
+ }
58
+
59
+ trait SemiGroup extends TypeClass {
60
+ def + (that : This ): This
61
+ }
62
+
63
+ trait Monoid extends SemiGroup {
64
+ class Static [This ] { def unit : This }
65
+ }
66
+
67
+ implicit object extend_Int_Monoid extends Monoid # Static [Int ] with Implementation [Int , Monoid ] {
68
+ def unit : Int = 0
69
+ def inject ($this : Int ) = new Monoid {
70
+ type This = Int
71
+ def + (that : This ): This = $this + that
72
+ }
73
+ }
74
+
75
+ implicit object extend_String_Monoid extends Monoid # Static [String ] with Implementation [String , Monoid ] {
76
+ def unit = " "
77
+ def inject ($this : String ): Monoid { type This = String } =
78
+ new Monoid {
79
+ type This = String
80
+ def + (that : This ): This = $this + that
81
+ }
82
+ }
83
+
84
+ def impl [From , To ](implicit ev : Implementation [From , To ]): Implementation [From , To ] =
85
+ ev
86
+
87
+ def sum [T ](xs : List [T ])(implicit $ev : Implementation [T , Monoid ]) = {
88
+ // val ev = impl[T, Monoid]
89
+ ($ev.statics.unit /: xs)((x, y) => $ev.inject(x) + y)
90
+ }
91
+ }
92
+
93
+ // Ord
94
+
95
+ trait Ord {
96
+ def compareTo (that : This ): Int
97
+ def < (that : This ) = compareTo < 0
98
+ def > (that : This ) = compareTo > 0
99
+ }
100
+
101
+ extend List [type T : Ord ] : Ord {
102
+ def compareTo (that : List [T ]): Int = (this , that) match {
103
+ case (Nil , Nil ) => 0
104
+ case (Nil , _) => - 1
105
+ case (_, Nil ) => + 1
106
+ case (x :: xs, y :: ys) =>
107
+ val fst = x.compareTo(y)
108
+ if (fst != 0 ) fst else xs.compareTo(ys)
109
+ }
110
+ }
111
+
112
+ // Functor and Monad
113
+
114
+ trait Functor [A ] {
115
+ object type ThisC [A ] <: Functor [A ]
116
+ object def pure[A ]: ThisC [A ]
117
+
118
+ def map [B ](f : A => B ): ThisC [B ]
119
+ }
120
+
121
+ // Generically, `pure[A]{.map(f)}^n`
122
+ def develop [A , F [X ] : Functor [X ]](n : Int , f : A => A ): F [A ] =
123
+ if (n == 0 ) Functor .objects[F ].pure[A ]
124
+ else develop[A , F ](n - 1 , f).map(f)
125
+
126
+ trait Monad [A ] extends Functor [A ] {
127
+ object type ThisC [A ] <: Monad [A ]
128
+
129
+ def flatMap [B ](f : A => ThisC [B ]): ThisC [B ]
130
+ def map [B ](f : A => B ) = this .flatMap(f.andThen(pure))
131
+ }
132
+
133
+ extend List [type T ] : Monad [T ] {
134
+ object type ThisC [A ] = List [A ]
135
+ object def pure[A ] = Nil
136
+
137
+ def flatMap [B ](f : A => List [B ]): List [B ] = this match {
138
+ case x :: xs => f(x) ++ xs.flatMap(f)
139
+ case Nil => Nil
140
+ }
141
+ }
142
+
143
+ extend (type T [X ]: Monad [X ])[T [type A ]] {
144
+ def flatten : T [A ] = this .flatMap(identity)
145
+ }
146
+
147
+ // Iterables
148
+
149
+ trait MonoIterable [A ] {
150
+ object type ThisC [A ] <: MonoIterable [A ]
151
+ object def empty : This [A ]
152
+ object def apply(xs : A * ): This [A ]
153
+
154
+ def filter (p : A => Boolean ): This [A ]
155
+ }
156
+
157
+ trait Iterable [A ] extends MonoIterable [A ] {
158
+ object type ThisC [A ] <: Iterable [A ]
159
+
160
+ def map [B ](f : A => B ): ThisC [B ]
161
+ def flatMap [B ](f : A => ThisC [B ]): ThisC [B ]
162
+ }
163
+
164
+ extend String : MonoIterable [Char ] {
165
+ object type ThisC [A ] = String
166
+ object def empty = " "
167
+ object def apply(xs : A * ) = xs.mkString
168
+
169
+ def filter (p : Char => Boolean ): String = ...
170
+ def map (f : Char => Char ): String = ...
171
+ }
172
+
173
+ extend String : Iterable [Char ] {
174
+ object type ThisC [A ] = IndexedSeq [A ]
175
+
176
+ def map [B ](f : Char => B ): IndexedSeq [B ] = ...
177
+ def flatMap [B ](f : Char => IndexedSeq [B ]): IndexedSeq [B ] = ...
178
+ }
179
+
180
+ extend List [type T ] : Iterable [T ] {
181
+ object type ThisC [A ] = List [A ]
182
+ object def empty = Nil
183
+ object def apply(xs : A * ) = (xs /: Nil )(_ :: _)
184
+
185
+ def filter (p : T => Boolean ): List [T ] = ...
186
+ def map [B ](f : T => B ): List [B ] = ...
187
+ def flatMap [B ](f : T => List [B ]): List [B ] = ...
188
+ }
189
+
190
+ class Foo {
191
+
192
+ }
193
+ object Foo {
194
+
195
+ }
196
+ }
0 commit comments