1
+ /** A possible type class encoding for
2
+
3
+ trait SemiGroup {
4
+ def add(that: This): This
5
+ }
6
+
7
+ trait Monoid extends SemiGroup
8
+ common {
9
+ def unit: This
10
+ }
11
+
12
+ extension IntOps for Int : Monoid {
13
+ def add(that: Int) = this + that
14
+ }
15
+ common {
16
+ def unit = 0
17
+ }
18
+
19
+ extension StringOps for String : Monoid {
20
+ def add(that: Int) = this ++ that
21
+ }
22
+ common {
23
+ def unit = ""
24
+ }
25
+
26
+ def sum[T: Monoid](xs: List[T]): T =
27
+ (instance[T, Monoid].unit /: xs)(_ `add` _)
28
+
29
+ */
30
+ object runtime {
31
+
32
+ trait TypeClass {
33
+ val common : TypeClassCommon
34
+ type This = common.This
35
+ }
36
+
37
+ trait TypeClassCommon { self =>
38
+ type This
39
+ type Instance <: TypeClass
40
+ def inject (x : This ): Instance { val common : self.type }
41
+ }
42
+
43
+ trait Extension [From , To <: TypeClass ] extends TypeClassCommon {
44
+ type This = From
45
+ type Instance = To
46
+ }
47
+
48
+ implicit def inject [From ](x : From )
49
+ (implicit ev : Extension [From , _]): ev.Instance { type This = From } =
50
+ ev.inject(x)
51
+ }
52
+ import runtime ._
53
+
54
+ object semiGroups {
55
+
56
+ trait SemiGroup extends TypeClass {
57
+ import common ._
58
+ def add (that : This ): This
59
+ }
60
+ trait SemiGroupCommon extends TypeClassCommon {
61
+ type Instance <: SemiGroup
62
+ }
63
+
64
+ trait Monoid extends SemiGroup {
65
+ val common : MonoidCommon
66
+ import common ._
67
+ }
68
+ trait MonoidCommon extends SemiGroupCommon {
69
+ type Instance <: Monoid
70
+ def unit : This
71
+ }
72
+
73
+ implicit object IntOps extends Extension [Int , Monoid ] with MonoidCommon { self =>
74
+ type This = Int
75
+ type Instance = Monoid
76
+ def unit : Int = 0
77
+ def inject ($this : Int ) = new Monoid {
78
+ val common : self.type = self
79
+ def add (that : This ): This = $this + that
80
+ }
81
+ }
82
+
83
+ implicit object StringOps extends Extension [String , Monoid ] with MonoidCommon { self =>
84
+ type This = String
85
+ type Instance = Monoid
86
+ def unit = " "
87
+ def inject ($this : String ) = new Monoid {
88
+ val common : self.type = self
89
+ def add (that : This ): This = $this .concat(that)
90
+ }
91
+ }
92
+
93
+ def sum [T ](xs : List [T ])(implicit $ev : Extension [T , Monoid ] with MonoidCommon ) =
94
+ (implicitly[Extension [T , Monoid ] with MonoidCommon ].unit /: xs)((x, y) => x `add` y)
95
+ }
96
+
97
+ /** Encoding for
98
+
99
+ trait Ord {
100
+ def compareTo(that: This): Int
101
+ def < (that: This) = compareTo(that) < 0
102
+ def > (that: This) = compareTo(that) > 0
103
+ }
104
+ common {
105
+ val minimum: This
106
+ }
107
+
108
+ extension IntOrd for Int : Ord {
109
+ def compareTo(that: Int) =
110
+ if (this < that) -1 else if (this > that) +1 else 0
111
+ }
112
+ common {
113
+ val minimum = Int.MinValue
114
+ }
115
+
116
+ extension ListOrd[T : Ord] for List[T] : Ord {
117
+ def compareTo(that: List[T]): Int = (this, that) match {
118
+ case (Nil, Nil) => 0
119
+ case (Nil, _) => -1
120
+ case (_, Nil) => +1
121
+ case (x :: xs, y :: ys) =>
122
+ val fst = x.compareTo(y)
123
+ if (fst != 0) fst else xs.compareTo(ys)
124
+ }
125
+ }
126
+ common {
127
+ val minimum = Nil
128
+ }
129
+
130
+ def min[T: Ord](x: T, y: T) = if (x < y) x else y
131
+
132
+ def inf[T: Ord](xs: List[T]): T = (instance[T, Ord].minimum /: xs)(_ `min` _)
133
+ */
134
+
135
+ object ord {
136
+
137
+ trait Ord extends TypeClass {
138
+ import common ._
139
+ def compareTo (that : This ): Int
140
+ def < (that : This ) = compareTo(that) < 0
141
+ def > (that : This ) = compareTo(that) > 0
142
+ }
143
+ trait OrdCommon extends TypeClassCommon {
144
+ type Instance <: Ord
145
+ def minimum : This
146
+ }
147
+
148
+ implicit object IntOrd extends Extension [Int , Ord ] with OrdCommon { self =>
149
+ type This = Int
150
+ type Instance = Ord
151
+ val minimum : Int = Int .MinValue
152
+ def inject ($this : Int ) = new Ord {
153
+ val common : self.type = self
154
+ def compareTo (that : This ): Int =
155
+ if (this < that) - 1 else if (this > that) + 1 else 0
156
+ }
157
+ }
158
+
159
+ class ListOrd [T ](implicit ev : Extension [T , Ord ] with OrdCommon )
160
+ extends Extension [List [T ], Ord ] with OrdCommon { self =>
161
+ type This = List [T ]
162
+ type Instance = Ord
163
+ def minimum : List [T ] = Nil
164
+ def inject ($this : List [T ]) = new Ord {
165
+ val common : self.type = self
166
+ def compareTo (that : List [T ]): Int = ($this , that) match {
167
+ case (Nil , Nil ) => 0
168
+ case (Nil , _) => - 1
169
+ case (_, Nil ) => + 1
170
+ case (x :: xs, y :: ys) =>
171
+ val fst = x.compareTo(y)
172
+ if (fst != 0 ) fst else xs.compareTo(ys)
173
+ }
174
+ }
175
+ }
176
+
177
+ implicit def listOrd [T ](implicit ev : Extension [T , Ord ] with OrdCommon ): ListOrd [T ] =
178
+ new ListOrd [T ]
179
+
180
+ def min [T ](x : T , y : T )(implicit ev : Extension [T , Ord ] with OrdCommon ): T =
181
+ if (x < y) x else y
182
+
183
+ def inf [T ](xs : List [T ])(implicit ev : Extension [T , Ord ] with OrdCommon ): T = {
184
+ val smallest = implicitly[Extension [T , Ord ] with OrdCommon ].minimum
185
+ (smallest /: xs)(min(_, _))
186
+ }
187
+ }
0 commit comments