@@ -29,6 +29,8 @@ object TypeLevel {
29
29
30
30
abstract class GenericProduct [T ] extends Generic [T ] {
31
31
type ElemTypes <: Tuple
32
+ type CaseLabel
33
+ type ElemLabels <: Tuple
32
34
def toProduct (x : T ): Product
33
35
def fromProduct (p : Product ): T
34
36
}
@@ -63,6 +65,8 @@ object Lst {
63
65
64
66
class GenericCons [T ] extends GenericProduct [Cons [T ]] {
65
67
type ElemTypes = (T , Lst [T ])
68
+ type CaseLabel = " Cons"
69
+ type ElemLabels = (" hd" , " tl" )
66
70
def toProduct (x : Cons [T ]): Product = x
67
71
def fromProduct (p : Product ): Cons [T ] =
68
72
new Cons (p.productElement(0 ).asInstanceOf [T ],
@@ -73,6 +77,8 @@ object Lst {
73
77
case object Nil extends Lst [Nothing ] {
74
78
class GenericNil extends GenericProduct [Nil .type ] {
75
79
type ElemTypes = Unit
80
+ type CaseLabel = " Nil"
81
+ type ElemLabels = Unit
76
82
def toProduct (x : Nil .type ): Product = EmptyProduct
77
83
def fromProduct (p : Product ): Nil .type = Nil
78
84
}
@@ -82,7 +88,7 @@ object Lst {
82
88
// three clauses that could be generated from a `derives` clause
83
89
implicit def derived$Eq [T : Eq ]: Eq [Lst [T ]] = Eq .derived
84
90
implicit def derived$Pickler [T : Pickler ]: Pickler [Lst [T ]] = Pickler .derived
85
- // implicit def derived$Show[T: Show]: Show[Lst[T]] = Show.derived
91
+ implicit def derived$Show [T : Show ]: Show [Lst [T ]] = Show .derived
86
92
}
87
93
88
94
// A typeclass
@@ -148,6 +154,8 @@ object Pair {
148
154
149
155
class GenericPair [T ] extends GenericProduct [Pair [T ]] {
150
156
type ElemTypes = (T , T )
157
+ type CaseLabel = " Pair"
158
+ type ElemLabels = (" x" , " y" )
151
159
def toProduct (x : Pair [T ]): Product = x
152
160
def fromProduct (p : Product ): Pair [T ] =
153
161
Pair (p.productElement(0 ).asInstanceOf , p.productElement(1 ).asInstanceOf )
@@ -157,7 +165,7 @@ object Pair {
157
165
// clauses that could be generated from a `derives` clause
158
166
implicit def derived$Eq [T : Eq ]: Eq [Pair [T ]] = Eq .derived
159
167
implicit def derived$Pickler [T : Pickler ]: Pickler [Pair [T ]] = Pickler .derived
160
- // implicit def derived$Show[T: Show]: Show[Pair[T]] = Show.derived
168
+ implicit def derived$Show [T : Show ]: Show [Pair [T ]] = Show .derived
161
169
}
162
170
163
171
sealed trait Either [+ L , + R ] extends Product with Serializable // derives Eq, Pickler, Show
@@ -181,7 +189,7 @@ object Either {
181
189
182
190
implicit def derived$Eq [L : Eq , R : Eq ]: Eq [Either [L , R ]] = Eq .derived
183
191
implicit def derived$Pickler [L : Pickler , R : Pickler ]: Pickler [Either [L , R ]] = Pickler .derived
184
- // implicit def derived$Show[L: Show, R: Show]: Show[Either[L, R]] = Show.derived
192
+ implicit def derived$Show [L : Show , R : Show ]: Show [Either [L , R ]] = Show .derived
185
193
}
186
194
187
195
case class Left [L ](elem : L ) extends Either [L , Nothing ]
@@ -191,6 +199,8 @@ object Left {
191
199
import TypeLevel ._
192
200
class GenericLeft [L ] extends GenericProduct [Left [L ]] {
193
201
type ElemTypes = L *: Unit
202
+ type CaseLabel = " Left"
203
+ type ElemLabels = " x" *: Unit
194
204
def toProduct (x : Left [L ]) = x
195
205
def fromProduct (p : Product ): Left [L ] = Left (p.productElement(0 ).asInstanceOf [L ])
196
206
}
@@ -201,6 +211,8 @@ object Right {
201
211
import TypeLevel ._
202
212
class GenericRight [R ] extends GenericProduct [Right [R ]] {
203
213
type ElemTypes = R *: Unit
214
+ type CaseLabel = " Right"
215
+ type ElemLabels = " x" *: Unit
204
216
def toProduct (x : Right [R ]) = x
205
217
def fromProduct (p : Product ): Right [R ] = Right (p.productElement(0 ).asInstanceOf [R ])
206
218
}
@@ -298,6 +310,63 @@ object Pickler {
298
310
}
299
311
}
300
312
313
+ // A third typeclass, making use of labels
314
+ trait Show [T ] {
315
+ def show (x : T ): String
316
+ }
317
+ object Show {
318
+ import scala .compiletime .{erasedValue , constValue }
319
+ import TypeLevel ._
320
+
321
+ inline def tryShow [T ](x : T ): String = implicit match {
322
+ case s : Show [T ] => s.show(x)
323
+ }
324
+
325
+ inline def showElems [Elems <: Tuple , Labels <: Tuple ](x : Product , n : Int ): List [String ] =
326
+ inline erasedValue[Elems ] match {
327
+ case _ : (elem *: elems1) =>
328
+ inline erasedValue[Labels ] match {
329
+ case _ : (label *: labels1) =>
330
+ val formal = constValue[label]
331
+ val actual = tryShow(x.productElement(n).asInstanceOf [elem])
332
+ s " $formal = $actual" :: showElems[elems1, labels1](x, n + 1 )
333
+ }
334
+ case _ : Unit =>
335
+ Nil
336
+ }
337
+
338
+ inline def showCase [T ](gp : GenericProduct [T ], x : T ): String = {
339
+ val labl = constValue[gp.CaseLabel ]
340
+ showElems[gp.ElemTypes , gp.ElemLabels ](gp.toProduct(x), 0 )
341
+ .mkString(s " $labl( " , " , " , " )" )
342
+ }
343
+
344
+ inline def showCases [T ](x : T , genSum : GenericSum [T ], ord : Int , n : Int ): String =
345
+ inline if (n == genSum.numberOfCases)
346
+ " "
347
+ else if (ord == n)
348
+ inline genSum.alternative(n) match {
349
+ case cas : GenericProduct [p] =>
350
+ showCase(cas, x.asInstanceOf [p])
351
+ }
352
+ else showCases[T ](x, genSum, ord, n + 1 )
353
+
354
+ inline def derived [T ](implicit ev : Generic [T ]): Show [T ] = new {
355
+ def show (x : T ): String = {
356
+ inline ev match {
357
+ case ev : GenericSum [T ] =>
358
+ showCases(x, ev, ev.ordinal(x), 0 )
359
+ case ev : GenericProduct [p] =>
360
+ showCase(ev, x)
361
+ }
362
+ }
363
+ }
364
+
365
+ implicit object IntShow extends Show [Int ] {
366
+ def show (x : Int ): String = x.toString
367
+ }
368
+ }
369
+
301
370
// Tests
302
371
object Test extends App {
303
372
import TypeLevel ._
@@ -349,7 +418,14 @@ object Test extends App {
349
418
assert(p1 == p1a)
350
419
assert(eqp.eql(p1, p1a))
351
420
421
+ def showPrintln [T : Show ](x : T ): Unit =
422
+ println(implicitly[Show [T ]].show(x))
423
+
424
+ showPrintln(xs)
425
+ showPrintln(xss)
426
+
352
427
val zs = Lst .Cons (Left (1 ), Lst .Cons (Right (Pair (2 , 3 )), Lst .Nil ))
428
+ showPrintln(zs)
353
429
354
430
def pickle [T : Pickler ](buf : mutable.ListBuffer [Int ], x : T ): Unit =
355
431
implicitly[Pickler [T ]].pickle(buf, x)
@@ -366,5 +442,6 @@ object Test extends App {
366
442
def eql [T : Eq ](x : T , y : T ) = implicitly[Eq [T ]].eql(x, y)
367
443
368
444
val zs1 = copy(zs)
445
+ showPrintln(zs1)
369
446
assert(eql(zs, zs1))
370
447
}
0 commit comments