|
| 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 | + static def unit: This |
| 9 | + } |
| 10 | +
|
| 11 | + extend Int : Monoid { |
| 12 | + def add(that: Int) = this + that |
| 13 | + static def unit = 0 |
| 14 | + } |
| 15 | +
|
| 16 | + extend String : Monoid { |
| 17 | + def add(that: Int) = this ++ that |
| 18 | + static def unit = "" |
| 19 | + } |
| 20 | +
|
| 21 | + def sum[T: Monoid](xs: List[T]): T = |
| 22 | + (instance[T, Monoid].unit /: xs)(_ `add` _) |
| 23 | +
|
| 24 | +*/ |
| 25 | +object runtime { |
| 26 | + |
| 27 | + trait TypeClass { |
| 28 | + type This |
| 29 | + type StaticPart[This] |
| 30 | + } |
| 31 | + |
| 32 | + trait Implementation[From] { |
| 33 | + type This = From |
| 34 | + type Implemented <: TypeClass |
| 35 | + def inject(x: From): Implemented { type This = From } |
| 36 | + } |
| 37 | + |
| 38 | + class CompanionOf[T] { type StaticPart[_] } |
| 39 | + |
| 40 | + def instance[From, To <: TypeClass]( |
| 41 | + implicit ev1: Implementation[From] { type Implemented = To }, |
| 42 | + ev2: CompanionOf[To]): Implementation[From] { type Implemented = To } & ev2.StaticPart[From] = |
| 43 | + ev1.asInstanceOf // can we avoid the cast? |
| 44 | + |
| 45 | + implicit def inject[From](x: From)( |
| 46 | + implicit ev1: Implementation[From]): ev1.Implemented { type This = From } = |
| 47 | + ev1.inject(x) |
| 48 | +} |
| 49 | + |
| 50 | +object semiGroups { |
| 51 | + import runtime._ |
| 52 | + |
| 53 | + trait SemiGroup extends TypeClass { |
| 54 | + def add(that: This): This |
| 55 | + } |
| 56 | + |
| 57 | + trait Monoid extends SemiGroup { |
| 58 | + type StaticPart[This] <: MonoidStatic[This] |
| 59 | + } |
| 60 | + abstract class MonoidStatic[This] { def unit: This } |
| 61 | + |
| 62 | + implicit def companionOfMonoid: CompanionOf[Monoid] { |
| 63 | + type StaticPart[X] = MonoidStatic[X] |
| 64 | + } = new CompanionOf[Monoid] { |
| 65 | + type StaticPart[X] = MonoidStatic[X] |
| 66 | + } |
| 67 | + |
| 68 | + implicit object extend_Int_Monoid extends MonoidStatic[Int] with Implementation[Int] { |
| 69 | + type Implemented = Monoid |
| 70 | + def unit: Int = 0 |
| 71 | + def inject($this: Int) = new Monoid { |
| 72 | + type This = Int |
| 73 | + def add(that: This): This = $this + that |
| 74 | + } |
| 75 | + } |
| 76 | + |
| 77 | + implicit object extend_String_Monoid extends MonoidStatic[String] with Implementation[String] { |
| 78 | + type Implemented = Monoid |
| 79 | + def unit = "" |
| 80 | + def inject($this: String): Monoid { type This = String } = |
| 81 | + new Monoid { |
| 82 | + type This = String |
| 83 | + def add(that: This): This = $this ++ that |
| 84 | + } |
| 85 | + } |
| 86 | + |
| 87 | + def sum[T](xs: List[T])(implicit $ev: Implementation[T] { type Implemented = Monoid } ) = { |
| 88 | + (instance[T, Monoid].unit /: xs)((x, y) => inject(x) `add` y) |
| 89 | + (instance[T, Monoid].unit /: xs)((x, y) => x `add` y) // fails in scalac and previous dotc. |
| 90 | + } |
| 91 | +} |
0 commit comments