Skip to content

Commit b8e0298

Browse files
committed
Add examples of abtract Nat implementations
* As case classes * As Int * As Int or BigInt to cover overflows
1 parent abdba3f commit b8e0298

File tree

2 files changed

+322
-0
lines changed

2 files changed

+322
-0
lines changed

tests/run/fully-abstract-nat.check

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
CaseClassImplementation
2+
underlying rep: Z()
3+
test1 OK
4+
test2 OK
5+
6+
underlying rep: S(S(S(Z())))
7+
test3 OK
8+
Succ(S(S(Z()))) = 3
9+
test4 OK
10+
Succ(S(S(Z()))) = 3
11+
12+
IntImplementation
13+
underlying rep: 0
14+
test1 OK
15+
test2 OK
16+
17+
underlying rep: 3
18+
test3 OK
19+
Succ(2) = 3
20+
test4 OK
21+
Succ(2) = 3
22+
23+
UnboundedIntImplementation
24+
underlying rep: 0
25+
test1 OK
26+
test2 OK
27+
28+
underlying rep: 3
29+
test3 OK
30+
Succ(2) = 3
31+
test4 OK
32+
Succ(2) = 3
33+
34+
test OK
35+
Succ(1267650600228229401496703205374) = 1267650600228229401496703205376

tests/run/fully-abstract-nat.scala

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
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("IntImplementation")
12+
testInterface(IntImplementation)
13+
14+
println()
15+
16+
println("UnboundedIntImplementation")
17+
testInterface(UnboundedIntImplementation)
18+
19+
println()
20+
21+
{
22+
import UnboundedIntImplementation._
23+
val large = (BigInt(1) << 100).asInstanceOf[Succ]
24+
large match {
25+
case Zero() => println("test fail")
26+
case s @ Succ(pred) =>
27+
println("test OK")
28+
println(s"Succ(${pred.pred}) = $s")
29+
}
30+
}
31+
}
32+
33+
def testInterface(numbers: Numbers): Unit = {
34+
import numbers._
35+
val zero = Zero()
36+
println("underlying rep: " + zero)
37+
38+
zero match {
39+
case Succ(_) => println("test1 fail")
40+
case Zero() => println("test1 OK")
41+
}
42+
43+
zero match {
44+
case _: Succ => println("test2 fail")
45+
case _: Zero => println("test2 OK")
46+
}
47+
48+
println()
49+
50+
val three = Succ(Succ(zero)).succ
51+
52+
println("underlying rep: " + three)
53+
54+
three match {
55+
case Zero() => println("test3 fail")
56+
case s @ Succ(pred) =>
57+
println("test3 OK")
58+
println(s"Succ($pred) = ${s.value}")
59+
}
60+
61+
three match {
62+
case _: Zero => println("test4 fail")
63+
case s: Succ =>
64+
println("test4 OK")
65+
println(s"Succ(${s.pred}) = ${s.value}")
66+
}
67+
}
68+
69+
}
70+
71+
abstract class Numbers {
72+
73+
// === Nat ==========================================
74+
// Represents:
75+
// trait Nat
76+
// case object Zero extends Nat
77+
// case class Succ(pred: Nat) extends Nat
78+
79+
type Nat
80+
implicit def natClassTag: ClassTag[Nat]
81+
82+
trait AbstractNat {
83+
def value: Int
84+
def succ: Succ
85+
}
86+
implicit def NatDeco(nat: Nat): AbstractNat
87+
88+
// --- Zero ----------------------------------------
89+
90+
type Zero <: Nat
91+
92+
implicit def zeroClassTag: ClassTag[Zero]
93+
94+
val Zero: ZeroExtractor
95+
abstract class ZeroExtractor {
96+
def apply(): Zero
97+
def unapply(zero: Zero): Boolean
98+
}
99+
100+
// --- Succ ----------------------------------------
101+
102+
type Succ <: Nat
103+
104+
implicit def succClassTag: ClassTag[Succ]
105+
106+
val Succ: SuccExtractor
107+
abstract class SuccExtractor {
108+
def apply(nat: Nat): Succ
109+
def unapply(x: Succ): Option[Nat]
110+
}
111+
112+
trait AbstractSucc {
113+
def pred: Nat
114+
}
115+
implicit def SuccDeco(succ: Succ): AbstractSucc
116+
117+
}
118+
119+
object CaseClassImplementation extends Numbers {
120+
121+
sealed trait N
122+
final case class Z() extends N
123+
final case class S(n: N) extends N
124+
125+
// === Nat ==========================================
126+
127+
type Nat = N
128+
129+
def natClassTag: ClassTag[Nat] = implicitly
130+
131+
implicit def NatDeco(nat: Nat): AbstractNat = new AbstractNat {
132+
def value: Int = nat match {
133+
case Succ(n) => 1 + n.value
134+
case _ => 0
135+
}
136+
def succ: Succ = Succ(nat)
137+
}
138+
139+
// --- Zero ----------------------------------------
140+
141+
type Zero = Z
142+
143+
def zeroClassTag: ClassTag[Zero] = implicitly
144+
145+
val Zero: ZeroExtractor = new ZeroExtractor {
146+
def apply(): Zero = new Z()
147+
def unapply(zero: Zero): Boolean = true // checked by class tag before calling the unapply
148+
}
149+
150+
// --- Succ ----------------------------------------
151+
152+
type Succ = S
153+
154+
def succClassTag: ClassTag[Succ] = implicitly
155+
156+
val Succ: SuccExtractor = new SuccExtractor {
157+
def apply(nat: Nat): Succ = S(nat)
158+
def unapply(succ: Succ): Option[Nat] = Some(succ.n) // checked by class tag before calling the unapply
159+
}
160+
161+
def SuccDeco(succ: Succ): AbstractSucc = new AbstractSucc {
162+
def pred: Nat = succ.n
163+
}
164+
165+
}
166+
167+
168+
object IntImplementation extends Numbers {
169+
170+
// === Nat ==========================================
171+
172+
type Nat = Int
173+
174+
def natClassTag: ClassTag[Nat] = intClassTag(_ >= 0)
175+
176+
implicit def NatDeco(nat: Nat): AbstractNat = new AbstractNat {
177+
def value: Int = nat
178+
def succ: Succ = nat + 1
179+
}
180+
181+
// --- Zero ----------------------------------------
182+
183+
type Zero = Int
184+
185+
def zeroClassTag: ClassTag[Zero] = intClassTag(_ == 0)
186+
187+
val Zero: ZeroExtractor = new ZeroExtractor {
188+
def apply(): Zero = 0
189+
def unapply(zero: Zero): Boolean = true // checked by class tag before calling the unapply
190+
}
191+
192+
// --- Succ ----------------------------------------
193+
194+
type Succ = Int
195+
196+
def succClassTag: ClassTag[Succ] = intClassTag(_ > 0)
197+
198+
val Succ: SuccExtractor = new SuccExtractor {
199+
def apply(nat: Nat): Succ = nat + 1
200+
def unapply(succ: Succ): Option[Nat] = Some(succ - 1) // checked by class tag before calling the unapply
201+
}
202+
203+
def SuccDeco(succ: Succ): AbstractSucc = new AbstractSucc {
204+
def pred: Nat = succ - 1
205+
}
206+
207+
private def intClassTag(cond: Int => Boolean): ClassTag[Int] = new ClassTag[Int] {
208+
def runtimeClass: Class[_] = classOf[Int]
209+
override def unapply(x: Any): Option[Int] = x match {
210+
case i: Int if cond(i) => Some(i)
211+
case _ => None
212+
}
213+
}
214+
215+
}
216+
217+
object UnboundedIntImplementation extends Numbers {
218+
219+
// === Nat ==========================================
220+
221+
type Nat = Any // Int | BigInt
222+
223+
def natClassTag: ClassTag[Nat] = new ClassTag[Any] {
224+
def runtimeClass: Class[_] = classOf[Any]
225+
override def unapply(x: Any): Option[Nat] = x match {
226+
case i: Int if i >= 0 => Some(i)
227+
case i: BigInt if i > Int.MaxValue => Some(i)
228+
case _ => None
229+
}
230+
}
231+
232+
implicit def NatDeco(nat: Nat): AbstractNat = new AbstractNat {
233+
def value: Int = nat match {
234+
case nat: Int => nat
235+
case _ => throw new Exception("Number too large: " + nat)
236+
}
237+
def succ: Succ = nat match {
238+
case nat: Int =>
239+
if (nat == Integer.MAX_VALUE) BigInt(nat) + 1
240+
else nat + 1
241+
case nat: BigInt => nat + 1
242+
}
243+
}
244+
245+
// --- Zero ----------------------------------------
246+
247+
type Zero = Int
248+
249+
def zeroClassTag: ClassTag[Zero] = new ClassTag[Int] {
250+
def runtimeClass: Class[_] = classOf[Int]
251+
override def unapply(x: Any): Option[Int] = if (x == 0) Some(0) else None
252+
}
253+
254+
object Zero extends ZeroExtractor {
255+
def apply(): Zero = 0
256+
def unapply(zero: Zero): Boolean = true // checked by class tag before calling the unapply
257+
}
258+
259+
// --- Succ ----------------------------------------
260+
261+
type Succ = Any // Int | BigInt
262+
263+
def succClassTag: ClassTag[Succ] = new ClassTag[Any] {
264+
def runtimeClass: Class[_] = classOf[Any]
265+
override def unapply(x: Any): Option[Succ] = x match {
266+
case i: Int if i > 0 => Some(i)
267+
case i: BigInt if i > Int.MaxValue => Some(i)
268+
case _ => None
269+
}
270+
}
271+
272+
object Succ extends SuccExtractor {
273+
def apply(nat: Nat): Succ = nat.succ
274+
def unapply(succ: Succ): Option[Nat] = Some(succ.pred) // succ > 0 checked by class tag before calling the unapply
275+
}
276+
277+
implicit def SuccDeco(succ: Succ): AbstractSucc = new AbstractSucc {
278+
def pred: Nat = succ match {
279+
case succ: Int => succ - 1 // succ > 0 checked by class tag before calling the unapply
280+
case succ: BigInt =>
281+
val n = succ - 1
282+
if (n.isValidInt) n.intValue()
283+
else n
284+
}
285+
}
286+
287+
}

0 commit comments

Comments
 (0)