How does Fin
actually work?
data Nat = Z | S Nat
data Fin : (n : Nat) -> Type where
FZ : Fin (S k)
FS : Fin k -> Fin (S k)
- Where does
k
come from? - Why isn't
FZ
always the value of(n: Nat)
+ 1? - How does
Fin
"know" not to exceed its type bound?
This mailing list talks about implicits, but I'm lost as to how and where these values come from.
Given this basic example:
t1 : Fin 3
t1 = FZ
What is t1
's value? t1's type is Fin 3
, but FZ experimentally (appears) to represent zero. Which is why we can "count" with it just like we do with Nat
:
t2 : Fin 3
t3 = FS (FS FZ) -- this is equal to 2?
But this confuses me given the constructor!
FZ : Fin (S k)
If we're saying that t1
has type Fin 3
, does that mean that k
takes on the value of the n
in the type? If that were the case, and FZ
calls S
on that Nat
, then why isn't FZ
representing 4?
This is obviously not the case.
So I'm completely and absolutely lost on how FZ acts like 0, and where k
comes from, and how the compiler knows when k
has become >= n
just based on this data type.
I think what's confusing you is that you're thinking
k
is the value of theFin n
. It's not. It's just book-keeping to make sure theFin n
is always less thann
.Where does k come from?
In
k
is an (erased) implicit argument. It's shorthand forso it's passed implicitly, but it's still an argument to
FZ
. In most cases, it can be unambiguously inferred from the context. The compiler will tell you if it can't.Why isn't
FZ
always the value of(n: Nat) + 1
?FZ
always represents zero*. Thisis the same as
It's a zero that's less than three. These are also all zero
How does Fin "know" not to exceed its type bound?
Since
FZ
is always zero, andFS FZ
is always one, and so on, it's impossible to express aFin n
with value greater than or equal ton
. Let's try to create aFin 2
of value two.To see why this won't compile, fill in the implicits (note that
FS
also has an implicit argument calledk
):We're creating a
Fin 2
so the outer-mostFS
must haveS k = 2
sok = 1
. Each successiveFS
we go down we reducek
by one (see the argument toFS
isFin k
to produce aFin (S k)
- so one less). Eventually we reachFZ
but by this point there's isn't aNat
to represent this value ofk
. The compiler balks with such a statementYou can do the same for a
Fin 2
of value three etc. Have a try.Other qus
Given
What is
t1
's value? It'sFZ
, andFZ
represents zero.Yes, it's two.
If we're saying that
t1
has typeFin 3
, does that mean thatk
takes on the value of then
in the type? If that were the case, andFZ
callsS
on thatNat
, then why isn'tFZ
representing 4?S k
takes on the value ofn
.*this is actually a matter convention, but I'll avoid confusing things by going into that