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