Skip to content

Commit bf17e3c

Browse files
committed
New typeclass encoding
1 parent 0848614 commit bf17e3c

File tree

1 file changed

+187
-0
lines changed

1 file changed

+187
-0
lines changed

tests/pos/typeclass-encoding2.scala

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
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+
common {
9+
def unit: This
10+
}
11+
12+
extension IntOps for Int : Monoid {
13+
def add(that: Int) = this + that
14+
}
15+
common {
16+
def unit = 0
17+
}
18+
19+
extension StringOps for String : Monoid {
20+
def add(that: Int) = this ++ that
21+
}
22+
common {
23+
def unit = ""
24+
}
25+
26+
def sum[T: Monoid](xs: List[T]): T =
27+
(instance[T, Monoid].unit /: xs)(_ `add` _)
28+
29+
*/
30+
object runtime {
31+
32+
trait TypeClass {
33+
val common: TypeClassCommon
34+
type This = common.This
35+
}
36+
37+
trait TypeClassCommon { self =>
38+
type This
39+
type Instance <: TypeClass
40+
def inject(x: This): Instance { val common: self.type }
41+
}
42+
43+
trait Extension[From, To <: TypeClass] extends TypeClassCommon {
44+
type This = From
45+
type Instance = To
46+
}
47+
48+
implicit def inject[From](x: From)
49+
(implicit ev: Extension[From, _]): ev.Instance { type This = From } =
50+
ev.inject(x)
51+
}
52+
import runtime._
53+
54+
object semiGroups {
55+
56+
trait SemiGroup extends TypeClass {
57+
import common._
58+
def add(that: This): This
59+
}
60+
trait SemiGroupCommon extends TypeClassCommon {
61+
type Instance <: SemiGroup
62+
}
63+
64+
trait Monoid extends SemiGroup {
65+
val common: MonoidCommon
66+
import common._
67+
}
68+
trait MonoidCommon extends SemiGroupCommon {
69+
type Instance <: Monoid
70+
def unit: This
71+
}
72+
73+
implicit object IntOps extends Extension[Int, Monoid] with MonoidCommon { self =>
74+
type This = Int
75+
type Instance = Monoid
76+
def unit: Int = 0
77+
def inject($this: Int) = new Monoid {
78+
val common: self.type = self
79+
def add(that: This): This = $this + that
80+
}
81+
}
82+
83+
implicit object StringOps extends Extension[String, Monoid] with MonoidCommon { self =>
84+
type This = String
85+
type Instance = Monoid
86+
def unit = ""
87+
def inject($this: String) = new Monoid {
88+
val common: self.type = self
89+
def add(that: This): This = $this.concat(that)
90+
}
91+
}
92+
93+
def sum[T](xs: List[T])(implicit $ev: Extension[T, Monoid] with MonoidCommon) =
94+
(implicitly[Extension[T, Monoid] with MonoidCommon].unit /: xs)((x, y) => x `add` y)
95+
}
96+
97+
/** Encoding for
98+
99+
trait Ord {
100+
def compareTo(that: This): Int
101+
def < (that: This) = compareTo(that) < 0
102+
def > (that: This) = compareTo(that) > 0
103+
}
104+
common {
105+
val minimum: This
106+
}
107+
108+
extension IntOrd for Int : Ord {
109+
def compareTo(that: Int) =
110+
if (this < that) -1 else if (this > that) +1 else 0
111+
}
112+
common {
113+
val minimum = Int.MinValue
114+
}
115+
116+
extension ListOrd[T : Ord] for List[T] : Ord {
117+
def compareTo(that: List[T]): Int = (this, that) match {
118+
case (Nil, Nil) => 0
119+
case (Nil, _) => -1
120+
case (_, Nil) => +1
121+
case (x :: xs, y :: ys) =>
122+
val fst = x.compareTo(y)
123+
if (fst != 0) fst else xs.compareTo(ys)
124+
}
125+
}
126+
common {
127+
val minimum = Nil
128+
}
129+
130+
def min[T: Ord](x: T, y: T) = if (x < y) x else y
131+
132+
def inf[T: Ord](xs: List[T]): T = (instance[T, Ord].minimum /: xs)(_ `min` _)
133+
*/
134+
135+
object ord {
136+
137+
trait Ord extends TypeClass {
138+
import common._
139+
def compareTo(that: This): Int
140+
def < (that: This) = compareTo(that) < 0
141+
def > (that: This) = compareTo(that) > 0
142+
}
143+
trait OrdCommon extends TypeClassCommon {
144+
type Instance <: Ord
145+
def minimum: This
146+
}
147+
148+
implicit object IntOrd extends Extension[Int, Ord] with OrdCommon { self =>
149+
type This = Int
150+
type Instance = Ord
151+
val minimum: Int = Int.MinValue
152+
def inject($this: Int) = new Ord {
153+
val common: self.type = self
154+
def compareTo(that: This): Int =
155+
if (this < that) -1 else if (this > that) +1 else 0
156+
}
157+
}
158+
159+
class ListOrd[T](implicit ev: Extension[T, Ord] with OrdCommon)
160+
extends Extension[List[T], Ord] with OrdCommon { self =>
161+
type This = List[T]
162+
type Instance = Ord
163+
def minimum: List[T] = Nil
164+
def inject($this: List[T]) = new Ord {
165+
val common: self.type = self
166+
def compareTo(that: List[T]): Int = ($this, that) match {
167+
case (Nil, Nil) => 0
168+
case (Nil, _) => -1
169+
case (_, Nil) => +1
170+
case (x :: xs, y :: ys) =>
171+
val fst = x.compareTo(y)
172+
if (fst != 0) fst else xs.compareTo(ys)
173+
}
174+
}
175+
}
176+
177+
implicit def listOrd[T](implicit ev: Extension[T, Ord] with OrdCommon): ListOrd[T] =
178+
new ListOrd[T]
179+
180+
def min[T](x: T, y: T)(implicit ev: Extension[T, Ord] with OrdCommon): T =
181+
if (x < y) x else y
182+
183+
def inf[T](xs: List[T])(implicit ev: Extension[T, Ord] with OrdCommon): T = {
184+
val smallest = implicitly[Extension[T, Ord] with OrdCommon].minimum
185+
(smallest /: xs)(min(_, _))
186+
}
187+
}

0 commit comments

Comments
 (0)