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