1
+ import scala .reflect .ClassTag
2
+
3
+ object Test {
4
+ def main (args : Array [String ]): Unit = {
5
+ println(" CaseClassImplementation" )
6
+ testInterface(CaseClassImplementation )
7
+
8
+ println()
9
+
10
+ println(" ListImplementation" )
11
+ testInterface(ListImplementation )
12
+ }
13
+
14
+ def testInterface (arithmetic : Arithmetic ): Unit = {
15
+ import arithmetic ._
16
+ val const1 = Constant (1 )
17
+ println(" underlying rep: " + const1.getClass)
18
+ println(const1.eval)
19
+
20
+ const1 match {
21
+ case AppliedOp (_, _, _) =>
22
+ println(" test1 fail" )
23
+ case c @ Constant (n) =>
24
+ println(" test1 OK" )
25
+ println(s " $n = ${c.eval}" )
26
+ }
27
+
28
+ const1 match {
29
+ case _ : AppliedOp =>
30
+ println(" test2 fail" )
31
+ case c : Constant =>
32
+ println(" test2 OK" )
33
+ println(s " ${c.num} = ${c.eval}" )
34
+ }
35
+ println()
36
+
37
+ // 1 + (2 * 3)
38
+ val applied = AppliedOp (Op .Puls (), Constant (1 ), AppliedOp (Op .Mult (), Constant (2 ), Constant (3 )))
39
+
40
+ println(" underlying rep: " + applied.getClass)
41
+ println(applied.eval)
42
+
43
+ applied match {
44
+ case c @ Constant (n) =>
45
+ println(" test3 fail" )
46
+ case a @ AppliedOp (op, x, y) =>
47
+ println(" test3 OK" )
48
+ println(s " AppliedOp( $op, $x, $y) = ${a.eval}" )
49
+ }
50
+
51
+ applied match {
52
+ case c : Constant =>
53
+ println(" test4 fail" )
54
+ case a : AppliedOp =>
55
+ println(" test4 OK" )
56
+ println(s " AppliedOp( ${a.op}, ${a.lhs}, ${a.rhs}) = ${a.eval}" )
57
+ }
58
+
59
+ }
60
+ }
61
+
62
+ abstract class Arithmetic {
63
+
64
+ // === Numbers ==========================================
65
+ // Represents:
66
+ // trait Number
67
+ // case class Constant(n: Int) extends Number
68
+ // case class AppliedOp(op: Op, lhs: Number, rhs: Number) extends Number
69
+
70
+ type Number
71
+ implicit def numberClassTag : ClassTag [Number ]
72
+
73
+ trait AbstractNumber {
74
+ def thisNumber : Number
75
+ def eval : Int = thisNumber match {
76
+ case Constant (n) => n
77
+ case AppliedOp (op, x, y) => op(x, y)
78
+ }
79
+ }
80
+ implicit def NumberDeco (t : Number ): AbstractNumber
81
+
82
+ // --- Constant ----------------------------------------
83
+
84
+ type Constant <: Number
85
+ implicit def constantClassTag : ClassTag [Constant ]
86
+
87
+ val Constant : ConstantExtractor
88
+ abstract class ConstantExtractor {
89
+ def apply (x : Int ): Constant
90
+ def unapply (x : Constant ): Option [Int ]
91
+ }
92
+ trait AbstractConstant {
93
+ def num : Int
94
+ }
95
+ implicit def ConstantDeco (t : Constant ): AbstractConstant
96
+
97
+ // --- AppliedOp ----------------------------------------
98
+
99
+ type AppliedOp <: Number
100
+ implicit def appliedOpClassTag : ClassTag [AppliedOp ]
101
+
102
+ trait AbstractAppliedOp {
103
+ def op : Op
104
+ def lhs : Number
105
+ def rhs : Number
106
+ }
107
+ implicit def AppliedOpDeco (t : AppliedOp ): AbstractAppliedOp
108
+
109
+ val AppliedOp : AppliedOpExtractor
110
+ abstract class AppliedOpExtractor {
111
+ def apply (op : Op , x : Number , y : Number ): AppliedOp
112
+ def unapply (x : AppliedOp ): Option [(Op , Number , Number )]
113
+ }
114
+
115
+ // === Operations =======================================
116
+ // Represents:
117
+ // trait Op
118
+ // case object Puls extends Op
119
+ // case object Mult extends Op
120
+
121
+ type Op
122
+ implicit def opClassTag : ClassTag [Op ]
123
+
124
+ trait AbstractOp {
125
+ def thisOp : Op
126
+ def apply (x : Number , y : Number ): Int = thisOp match {
127
+ case Op .Puls () => x.eval + y.eval
128
+ case Op .Mult () => x.eval * y.eval
129
+ }
130
+ }
131
+ implicit def OpDeco (t : Op ): AbstractOp
132
+
133
+ val Op : OpModule
134
+ abstract class OpModule {
135
+ val Puls : PulsExtractor
136
+ abstract class PulsExtractor {
137
+ def apply (): Op
138
+ def unapply (x : Op ): Boolean
139
+ }
140
+
141
+ val Mult : MultExtractor
142
+ abstract class MultExtractor {
143
+ def apply (): Op
144
+ def unapply (x : Op ): Boolean
145
+ }
146
+ }
147
+ }
148
+
149
+ object CaseClassImplementation extends Arithmetic {
150
+
151
+ // === Numbers ==========================================
152
+ // Represented as case classes
153
+
154
+ sealed trait Num
155
+ final case class Const (n : Int ) extends Num
156
+ final case class App (op : Op , x : Num , y : Num ) extends Num
157
+
158
+ type Number = Num
159
+
160
+ def numberClassTag : ClassTag [Number ] = implicitly
161
+
162
+ def NumberDeco (t : Number ): AbstractNumber = new AbstractNumber {
163
+ def thisNumber : Number = t
164
+ }
165
+
166
+ // --- Constant ----------------------------------------
167
+
168
+ type Constant = Const
169
+ def constantClassTag : ClassTag [Constant ] = implicitly
170
+
171
+ def ConstantDeco (const : Constant ): AbstractConstant = new AbstractConstant {
172
+ def num : Int = const.n
173
+ }
174
+
175
+ object Constant extends ConstantExtractor {
176
+ def apply (x : Int ): Constant = Const (x)
177
+ def unapply (x : Constant ): Option [Int ] = Some (x.n)
178
+ }
179
+
180
+ // --- AppliedOp ----------------------------------------
181
+
182
+ def AppliedOpDeco (t : AppliedOp ): AbstractAppliedOp = new AbstractAppliedOp {
183
+ def op : Op = t.op
184
+ def lhs : Number = t.x
185
+ def rhs : Number = t.y
186
+ }
187
+
188
+ type AppliedOp = App
189
+ def appliedOpClassTag : ClassTag [AppliedOp ] = implicitly
190
+
191
+ object AppliedOp extends AppliedOpExtractor {
192
+ def apply (op : Op , x : Number , y : Number ): AppliedOp = App (op, x, y)
193
+ def unapply (app : AppliedOp ): Option [(Op , Number , Number )] = Some ((app.op, app.x, app.y))
194
+ }
195
+
196
+ // === Operations =======================================
197
+ // Represented as case classes
198
+
199
+ sealed trait Operation
200
+ case object PlusOp extends Operation
201
+ case object MultOp extends Operation
202
+
203
+ type Op = Operation
204
+ def opClassTag : ClassTag [Op ] = implicitly
205
+
206
+ def OpDeco (t : Op ): AbstractOp = new AbstractOp {
207
+ def thisOp : Op = t
208
+ }
209
+
210
+ object Op extends OpModule {
211
+ object Puls extends PulsExtractor {
212
+ def apply (): Op = PlusOp
213
+ def unapply (x : Op ): Boolean = x == PlusOp
214
+ }
215
+ object Mult extends MultExtractor {
216
+ def apply (): Op = MultOp
217
+ def unapply (x : Op ): Boolean = x == MultOp
218
+ }
219
+ }
220
+ }
221
+
222
+ object ListImplementation extends Arithmetic {
223
+ // Logically represented as:
224
+ // type Number <: List[Any]
225
+ // type Constant <: Number // List(n: Int)
226
+ // type AppliedOp <: Number // List(op: Op, lhs: Number, rhs: Number)
227
+ //
228
+ // type Op <: List[Any] // List(id: "+" | "*")
229
+
230
+ // === Numbers ==========================================
231
+
232
+ type Number = List [Any ]
233
+
234
+ def numberClassTag : ClassTag [Number ] = new ClassTag [Number ] {
235
+ def runtimeClass : Class [_] = classOf [List [_]]
236
+ override def unapply (x : Any ): Option [List [Any ]] = x match {
237
+ case ls : List [Any ] if ls.length == 3 || (ls.length == 1 && ls(0 ).isInstanceOf [Int ]) =>
238
+ // Test that it is one of:
239
+ // type Constant <: Number // List(n: Int)
240
+ // type AppliedOp <: Number // List(op: Op, lhs: Number, rhs: Number)
241
+ Some (ls)
242
+ case _ => None
243
+ }
244
+ }
245
+
246
+ def NumberDeco (t : Number ): AbstractNumber = new AbstractNumber {
247
+ def thisNumber : Number = t
248
+ }
249
+
250
+ // --- Constant ----------------------------------------
251
+
252
+ type Constant = List [Any ] // List(n: Int)
253
+ def constantClassTag : ClassTag [Constant ] = new ClassTag [Constant ] {
254
+ def runtimeClass : Class [_] = classOf [List [_]]
255
+ override def unapply (x : Any ): Option [List [Any ]] = x match {
256
+ case ls : List [Any ] if ls.length == 1 && ls(0 ).isInstanceOf [Int ] =>
257
+ // Test that it is:
258
+ // type Constant <: Number // List(n: Int)
259
+ Some (ls)
260
+ case _ => None
261
+ }
262
+ }
263
+
264
+ def ConstantDeco (const : Constant ): AbstractConstant = new AbstractConstant {
265
+ def num : Int = const(0 ).asInstanceOf [Int ]
266
+ }
267
+
268
+ object Constant extends ConstantExtractor {
269
+ def apply (x : Int ): Constant = List (x)
270
+ def unapply (x : Constant ): Option [Int ] = Some (ConstantDeco (x).num)
271
+ }
272
+
273
+ // --- AppliedOp ----------------------------------------
274
+
275
+ def AppliedOpDeco (t : AppliedOp ): AbstractAppliedOp = new AbstractAppliedOp {
276
+ def op : Op = t(0 ).asInstanceOf [Op ]
277
+ def lhs : Number = t(1 ).asInstanceOf [Number ]
278
+ def rhs : Number = t(2 ).asInstanceOf [Number ]
279
+ }
280
+
281
+ type AppliedOp = List [Any ] // List(op: Op, lhs: Number, rhs: Number)
282
+ def appliedOpClassTag : ClassTag [AppliedOp ] = new ClassTag [AppliedOp ] {
283
+ def runtimeClass : Class [_] = classOf [List [_]]
284
+ override def unapply (x : Any ): Option [List [Any ]] = x match {
285
+ case ls : List [Any ] if ls.length == 3 =>
286
+ // Test that it is:
287
+ // type AppliedOp <: Number // List(op: Op, lhs: Number, rhs: Number)
288
+ Some (ls)
289
+ case _ => None
290
+ }
291
+ }
292
+
293
+ object AppliedOp extends AppliedOpExtractor {
294
+ def apply (op : Op , x : Number , y : Number ): AppliedOp = List (op, x, y)
295
+ def unapply (app : AppliedOp ): Option [(Op , Number , Number )] = {
296
+ val app2 = AppliedOpDeco (app)
297
+ Some ((app2.op, app2.lhs, app2.rhs))
298
+ }
299
+ }
300
+
301
+ // === Operations =======================================
302
+
303
+ type Op = List [Any ]
304
+ def opClassTag : ClassTag [Op ] = new ClassTag [Constant ] {
305
+ def runtimeClass : Class [_] = classOf [List [_]]
306
+ override def unapply (x : Any ): Option [List [Any ]] = x match {
307
+ case op @ ((" +" | " *" ) :: Nil ) =>
308
+ // Test that it is:
309
+ // type Op <: List[Any] // List(id: "+" | "*")
310
+ Some (op)
311
+ case _ => None
312
+ }
313
+ }
314
+
315
+ def OpDeco (t : Op ): AbstractOp = new AbstractOp {
316
+ def thisOp : Op = t
317
+ }
318
+
319
+ object Op extends OpModule {
320
+ object Puls extends PulsExtractor {
321
+ def apply (): Op = List (" +" )
322
+ def unapply (x : Op ): Boolean = x(0 ) == " +"
323
+ }
324
+ object Mult extends MultExtractor {
325
+ def apply (): Op = List (" *" )
326
+ def unapply (x : Op ): Boolean = x(0 ) == " *"
327
+ }
328
+ }
329
+ }
0 commit comments