Skip to content

Commit 94d1281

Browse files
committed
Add Scala Workshop 25 examples
1 parent 8cdc5c2 commit 94d1281

File tree

6 files changed

+238
-5
lines changed

6 files changed

+238
-5
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
type Pos = { v: Int with v >= 0 }
2+
3+
@main def main =
4+
val xs = List(-1,2,-2,1)
5+
xs.collect { case x: Int => x } : List[Pos] // error
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
@main def main =
2+
3+
// Specification using qualified types
4+
{
5+
def zip[A, B](as: List[A], bs: List[B] with bs.size == as.size):
6+
{l: List[(A, B)] with l.size == as.size}
7+
= ???
8+
9+
def concat[T](as: List[T], bs: List[T]):
10+
{rs: List[T] with rs.size == as.size + bs.size}
11+
= ???
12+
13+
val xs: List[Int] = ???
14+
val ys: List[Int] = ???
15+
zip(concat(xs, ys), concat(ys, xs))
16+
zip(concat(xs, ys), concat(xs, xs)) // error
17+
}
18+
19+
// Syntax
20+
{
21+
{
22+
type NonEmptyList[A] = { l: List[A] with l.nonEmpty }
23+
24+
// Not to be confused with structural types
25+
case class Box(value: Any)
26+
type IntBox = Box { val value: Int }
27+
}
28+
29+
// Shortand
30+
{
31+
def zip[A, B](as: List[A], bs: List[B] with bs.size == as.size) = ???
32+
}
33+
}
34+
35+
// Valid/invalid predicates
36+
{
37+
{
38+
var x = 3
39+
val y: Int with y == 3 = x // error: ⛔️ x is mutable
40+
}
41+
42+
{
43+
val x = 3
44+
val y: Int with y == 3 = x // okay
45+
}
46+
47+
{
48+
class Box(val value: Int)
49+
val b: Box with b == Box(3) = Box(3) // error: ⛔️ Box has equality by reference
50+
}
51+
52+
{
53+
case class Box(value: Int)
54+
val b: Box with b == Box(3) = Box(3) // okay
55+
}
56+
}
57+
58+
// Selfification
59+
{
60+
val x: Int = ???
61+
val y: Int with (y == x + 1) = x + 1
62+
63+
def f(x: Int): Int = ???
64+
val z: Int with (z == x + f(x)) = x + f(x)
65+
}
66+
67+
// Runtime checks
68+
{
69+
val idRegex = "^[a-zA-Z_][a-zA-Z0-9_]*$"
70+
type ID = {s: String with s.matches(idRegex)}
71+
72+
{
73+
"a2e7-e89b" match
74+
case _: ID => // matched
75+
case _ => // didn't match
76+
}
77+
78+
{
79+
val id: ID = "a2e7-e89b".runtimeChecked
80+
}
81+
82+
{
83+
val id: ID =
84+
if ("a2e7-e89b".matches(idRegex)) "a2e7-e89b".asInstanceOf[ID]
85+
else throw new IllegalArgumentException()
86+
}
87+
88+
{
89+
type Pos = { v: Int with v >= 0 }
90+
91+
val xs = List(-1,2,-2,1)
92+
xs.collect { case x: Pos => x } : List[Pos]
93+
}
94+
}
95+
96+
// Subtyping
97+
{
98+
{
99+
val x: Int = ???
100+
val y: Int = ???
101+
summon[{v: Int with v == 1 + 1} =:= {v: Int with v == 2}]
102+
summon[{v: Int with v == x + 1} =:= {v: Int with v == 1 + x}]
103+
summon[{v: Int with v == y + x} =:= {v: Int with v == x + y}]
104+
summon[{v: Int with v == x + 3 * y} =:= {v: Int with v == 2 * y + (x + y)}]
105+
}
106+
107+
{
108+
val x: Int = ???
109+
val y: Int = x + 1
110+
summon[{v: Int with v == y} =:= {v: Int with v == x + 1}]
111+
}
112+
113+
{
114+
val a: Int = ???
115+
val b: Int = ???
116+
summon[{v: Int with v == a && a == b} <:< {v: Int with v == b}]
117+
def f(x: Int): Int = ???
118+
summon[{v: Int with a == b} <:< {v: Int with f(a) == f(b)}]
119+
}
120+
121+
{
122+
summon[3 <:< {v: Int with v == 3}]
123+
}
124+
}
125+
126+
// Backup slides about type-level programming with existing Scala features
127+
{
128+
def checkSame(dimA: Int, dimB: dimA.type): Unit = ()
129+
checkSame(3, 3) // ok
130+
checkSame(3, 4) // error
131+
132+
{
133+
val x = 3
134+
val y = 3
135+
checkSame(x, y) // error
136+
}
137+
138+
{
139+
val x2: 3 = 3
140+
val y3: 3 = 3
141+
checkSame(x2, y3) // ok
142+
}
143+
144+
def readInt(): Int = ???
145+
146+
{
147+
val x: Int = readInt()
148+
val y = x
149+
val z = y
150+
checkSame(y, z) // error
151+
}
152+
153+
{
154+
val x: Int = readInt()
155+
val y: x.type = x
156+
val z: x.type = x
157+
checkSame(y, z) // okay
158+
}
159+
160+
161+
{
162+
val x: Int = readInt()
163+
val y: Int = readInt()
164+
val z = x + y
165+
val a = y + x
166+
checkSame(z, a) // error
167+
}
168+
169+
{
170+
import scala.compiletime.ops.int.+
171+
val x: 3 = 3
172+
val y: 5 = 5
173+
val z: x.type + y.type = x + y
174+
val a: y.type + x.type = y + x
175+
}
176+
177+
{
178+
import scala.compiletime.ops.int.+
179+
val x: Int = readInt()
180+
val y: Int = readInt()
181+
val z: x.type + y.type = x + y // error
182+
val a: y.type + x.type = y + x // error
183+
checkSame(z, a) // error
184+
}
185+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
type Pos = { v: Int with v >= 0 }
2+
type Neg = { v: Int with v < 0 }
3+
4+
trait Show[-A]:
5+
def apply(a: A): String
6+
7+
given show1: Show[Pos] with
8+
def apply(a: Pos): String = "I am a positive integer!"
9+
10+
given show2: Show[Neg] with
11+
def apply(a: Neg): String = "I am a negative integer!"
12+
13+
def show[A](a: A)(using s: Show[A]): String = s.apply(a)
14+
15+
def f(x: Int with x == 42, y: Int with y == -42): Unit =
16+
println(show(x)) // I am a positive integer!
17+
println(show(y)) // I am a negative integer!
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
type Pos = { v: Int with v >= 0 }
2+
3+
@main def main =
4+
val xs = List(-1,2,-2,1)
5+
xs.collect { case x: Pos => x } : List[Pos]
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
type PosInt = {v: Int with v > 0}
1+
type Pos = {v: Int with v > 0}
22

3-
4-
def inc(x: PosInt): PosInt = (x + 1).runtimeChecked
3+
def inc(x: Pos): Pos = (x + 1).runtimeChecked
54

65
@main def Test =
7-
val l: List[PosInt] = List(1,2,3)
8-
val l2: List[PosInt] = l.map(inc)
6+
val l: List[Pos] = List(1,2,3)
7+
val l2 = l.map(inc)
8+
l2: List[Pos]
99
()
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
type Pos = {v: Int with v >= 0}
2+
type Matrix[T] = List[List[T]]
3+
4+
def length[T](v: List[T]): Pos =
5+
v.length.runtimeChecked
6+
7+
def width[T](m: Matrix[T]): Pos =
8+
if m.isEmpty then 0 else length(m.head)
9+
10+
def height[T](m: Matrix[T]): Pos =
11+
length(m)
12+
13+
def tabulate[T](rows: Pos, cols: Pos, f: (r: Pos with r <= rows, c: Pos with c <= cols) => T)
14+
: {r: Matrix[T] with width(r) == cols && height(r) == rows} =
15+
List.tabulate(rows, cols)((r, c) => f(r.runtimeChecked, c.runtimeChecked)).runtimeChecked
16+
17+
def transpose[T](m: Matrix[T]): {r: Matrix[T] with width(r) == height(m) && height(r) == width(m)} =
18+
val newWidth = height(m)
19+
val newHeight = width(m)
20+
tabulate(newHeight, newWidth, (r, c) => m(r)(c))
21+

0 commit comments

Comments
 (0)