Skip to content

Commit 51bff8d

Browse files
committed
Some small updates and variants to blySkyExtensions
1 parent 09aa5d2 commit 51bff8d

File tree

3 files changed

+146
-28
lines changed

3 files changed

+146
-28
lines changed

tests/pending/pos/blueSkyExtensions.scala

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,17 @@ object blueSkyExtensions {
3232

3333
extend Int : Monoid {
3434
static def unit = 0
35-
3635
def + (that: Int) = this + that
3736
}
3837

3938
extend String : Monoid {
4039
static def unit = ""
41-
4240
def + (that: Int) = this ++ that
4341
}
4442

43+
def sum[T: Monoid](xs: List[T]): T =
44+
(instance[T, Monoid].unit /: xs)(_ `add` _)
45+
4546
// Ord
4647

4748
trait Ord {
@@ -64,10 +65,8 @@ object blueSkyExtensions {
6465
// Functor and Monad
6566

6667
trait Functor[A] {
67-
static type ThisC[A] <: Functor[A]
68-
static def pure[A]: ThisC[A]
69-
70-
def map[B](f: A => B): ThisC[B]
68+
static def pure[A]: This[A]
69+
def map[B](f: A => B): This[B]
7170
}
7271

7372
// Generically, `pure[A]{.map(f)}^n`
@@ -76,14 +75,11 @@ object blueSkyExtensions {
7675
else develop[A, F](n - 1, f).map(f)
7776

7877
trait Monad[A] extends Functor[A] {
79-
static type ThisC[A] <: Monad[A]
80-
81-
def flatMap[B](f: A => ThisC[B]): ThisC[B]
78+
def flatMap[B](f: A => This[B]): This[B]
8279
def map[B](f: A => B) = this.flatMap(f.andThen(pure))
8380
}
8481

8582
extend List[type T] : Monad[T] {
86-
static type ThisC[A] = List[A]
8783
static def pure[A] = Nil
8884

8985
def flatMap[B](f: A => List[B]): List[B] = this match {
@@ -99,22 +95,19 @@ object blueSkyExtensions {
9995
// Iterables
10096

10197
trait MonoIterable[A] {
102-
static type ThisC[A] <: MonoIterable[A]
10398
static def empty: This[A]
10499
static def apply(xs: A*): This[A]
105100

106101
def filter(p: A => Boolean): This[A]
107102
}
108103

109104
trait Iterable[A] extends MonoIterable[A] {
110-
static type ThisC[A] <: Iterable[A]
111-
112-
def map[B](f: A => B): ThisC[B]
113-
def flatMap[B](f: A => ThisC[B]): ThisC[B]
105+
def map[B](f: A => B): This[B]
106+
def flatMap[B](f: A => This[B]): This[B]
114107
}
115108

116109
extend String : MonoIterable[Char] {
117-
static type ThisC[A] = String
110+
static type This[A] = String
118111
static def empty = ""
119112
static def apply(xs: A*) = xs.mkString
120113

@@ -123,14 +116,14 @@ object blueSkyExtensions {
123116
}
124117

125118
extend String : Iterable[Char] {
126-
static type ThisC[A] = IndexedSeq[A]
119+
static type This[A] = IndexedSeq[A]
127120

128121
def map[B](f: Char => B): IndexedSeq[B] = ...
129122
def flatMap[B](f: Char => IndexedSeq[B]): IndexedSeq[B] = ...
130123
}
131124

132125
extend List[type T] : Iterable[T] {
133-
static type ThisC[A] = List[A]
126+
static type This[A] = List[A]
134127
static def empty = Nil
135128
static def apply(xs: A*) = (xs /: Nil)(_ :: _)
136129

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
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+
extension IntMonoid for Int : Monoid {
34+
static def unit = 0
35+
def + (that: Int) = this + that
36+
}
37+
38+
extension StringMonoid for String : Monoid {
39+
static def unit = ""
40+
def + (that: Int) = this ++ that
41+
}
42+
43+
def sum[T: Monoid](xs: List[T]): T =
44+
(instance[T, Monoid].unit /: xs)(_ `add` _)
45+
46+
// Ord
47+
48+
trait Ord {
49+
def compareTo(that: This): Int
50+
def < (that: This) = compareTo < 0
51+
def > (that: This) = compareTo > 0
52+
}
53+
54+
extension ListOrd[T : Ord] for List[T] : Ord {
55+
def compareTo(that: List[T]): Int = (this, that) match {
56+
case (Nil, Nil) => 0
57+
case (Nil, _) => -1
58+
case (_, Nil) => +1
59+
case (x :: xs, y :: ys) =>
60+
val fst = x.compareTo(y)
61+
if (fst != 0) fst else xs.compareTo(ys)
62+
}
63+
}
64+
65+
// Functor and Monad
66+
67+
trait Functor[A] {
68+
static def pure[A]: This[A]
69+
def map[B](f: A => B): This[B]
70+
}
71+
72+
// Generically, `pure[A]{.map(f)}^n`
73+
def develop[A, F[X] : Functor[X]](n: Int, f: A => A): F[A] =
74+
if (n == 0) Functor.statics[F].pure[A]
75+
else develop[A, F](n - 1, f).map(f)
76+
77+
trait Monad[A] extends Functor[A] {
78+
def flatMap[B](f: A => This[B]): This[B]
79+
def map[B](f: A => B) = this.flatMap(f.andThen(pure))
80+
}
81+
82+
extension ListMonad[T] for List[T] : Monad[T] {
83+
static def pure[A] = Nil
84+
85+
def flatMap[B](f: A => List[B]): List[B] = this match {
86+
case x :: xs => f(x) ++ xs.flatMap(f)
87+
case Nil => Nil
88+
}
89+
}
90+
91+
extension MonadFlatten[T[X]: Monad[X]] for T[T[A]] {
92+
def flatten: T[A] = this.flatMap(identity)
93+
}
94+
95+
// Iterables
96+
97+
trait MonoIterable[A] {
98+
static def empty: This[A]
99+
static def apply(xs: A*): This[A]
100+
101+
def filter(p: A => Boolean): This[A]
102+
}
103+
104+
trait Iterable[A] extends MonoIterable[A] {
105+
def map[B](f: A => B): This[B]
106+
def flatMap[B](f: A => This[B]): This[B]
107+
}
108+
109+
extension StringMonoIterable for String : MonoIterable[Char] {
110+
static type This[A] = String
111+
static def empty = ""
112+
static def apply(xs: A*) = xs.mkString
113+
114+
def filter(p: Char => Boolean): String = ...
115+
def map(f: Char => Char): String = ...
116+
}
117+
118+
extension StringIterable for String : Iterable[Char] {
119+
static type This[A] = IndexedSeq[A]
120+
121+
def map[B](f: Char => B): IndexedSeq[B] = ...
122+
def flatMap[B](f: Char => IndexedSeq[B]): IndexedSeq[B] = ...
123+
}
124+
125+
extension ListIterable[T] for List[T] : Iterable[T] {
126+
static type This[A] = List[A]
127+
static def empty = Nil
128+
static def apply(xs: A*) = (xs /: Nil)(_ :: _)
129+
130+
def filter(p: T => Boolean): List[T] = ...
131+
def map[B](f: T => B): List[B] = ...
132+
def flatMap[B](f: T => List[B]): List[B] = ...
133+
}
134+
}

tests/pending/pos/blueSkyExtensions2.scala

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,7 @@ object blueSkyExtensions {
112112
// Functor and Monad
113113

114114
trait Functor[A] {
115-
object type ThisC[A] <: Functor[A]
116-
object def pure[A]: ThisC[A]
117-
115+
static def pure[A]: This[A]
118116
def map[B](f: A => B): ThisC[B]
119117
}
120118

@@ -186,11 +184,4 @@ object blueSkyExtensions {
186184
def map[B](f: T => B): List[B] = ...
187185
def flatMap[B](f: T => List[B]): List[B] = ...
188186
}
189-
190-
class Foo {
191-
192-
}
193-
object Foo {
194-
195-
}
196187
}

0 commit comments

Comments
 (0)