Phantom Types in Scala 3
I'm recently migrating some libs and projects to Scala 3, I guess it would be very helpful to me or anyone interested to learn some new functional programming features that Scala 3 is bringing to us.
- Rank N Types
- FunctionK
- GADT
- Phantom Types
- Dependent Types
- "First Class" Types
- Type Classes
- Generic Type Class Derivation
Source code 👉 https://github.com/jcouyang/meow
Phantom Types are types on the left-hand side, but not on the right-hand side, which means the types that you don't actually need, to construct a data.
We actually met phantom type already in the SafeList example in GADT.
Here is a better one, we can put more info other than just Empty, NonEmpty in the type.
We can have length info in type as well, then we got a type safe Vector:
enum Nat {
case Zero
case Succ[A]()
}
import Nat._
type Nat2 = Succ[Succ[Zero.type]]
type Nat3 = Succ[Succ[Succ[Zero.type]]]
enum Vector[+N <: Nat, +A] {
case Cons(head: A, tail: Vector[N, A]) extends Vector[Succ[N], A]
case Nil extends Vector[Zero.type, Nothing]
}
import Vector._
val vector2: Vector[Nat2, Int] = Cons(1, Cons(2, Nil))
val vector3: Vector[Nat3, Int] = Cons(1, Cons(2, Cons(3, Nil)))
See the type Nat2 does only appear on the left hand side. Cons don't need anything
about Nat to create a Vector.
We know that for Scala List, if we call head, it could cause run time error when
the list is empty.
When we have the length info tagged into the Vector[N, A], we can actually create
a type level safe head, let us call it typeSafeHead:
def typeSafeHead[A](vec: Vector[Succ[Nat], A]):A = vec match
case Cons(head, _) => head
When you have some code that trying to get head from Nil, the compiler will tell you:
typeSafeHead(Nil)
Found: (Main.Vector.Nil : Main.Vector[(Main.Nat.Zero : Main.Nat), Nothing]) Required: Main.Vector[Main.Nat.Succ[Main.Nat], Any]
Similarly, you can easily create safe second as well, by counting how many Succ there are in Nat at type level.
Try it online at Scastie: https://scastie.scala-lang.org/jcouyang/JTX3OFXrTCOuq6LNfgRj8Q/8
Or clone the repo and sbt test: https://github.com/jcouyang/meow