Consider this as a first attempt:
go : ? {m α} {A : Set α} -> Fin m -> (xs : List A) -> List (Fin (m + length xs) × A)
go i [] = []
go i (x ∷ xs) = (inject+ _ i , x) ∷ {!go (suc i) xs!}
i
grows at each recursive call as it should, but there is a mismatch:
the type of the goal is List (Fin (.m + suc (length xs)) × .A)
the type of the expression insise the hole is List (Fin (suc (.m + length xs)) × .A)
It's easy to prove that two types are equal, but it's also dirty. This is a common problem: one argument grows and the other lowers, so we need definitionally commutative _+_
to handle both the cases, but there is no way to define it. The solution is to use CPS:
go : ? {α} {A : Set α} -> (k : ? -> ?) -> (xs : List A) -> List (Fin (k (length xs)) × A)
go k [] = []
go k (x ∷ xs) = ({!!} , x) ∷ go (k ° suc) xs
(k ° suc) (length xs)
is the same thing as k (length (x ∷ xs))
, hence the mismatch is fixed, but what is i
now? The type of the hole is Fin (k (suc (length xs)))
and it's uninhabited in the current context, so let's introduce some inhabitant:
go : ? {α} {A : Set α}
-> (k : ? -> ?)
-> (? {n} -> Fin (k (suc n)))
-> (xs : List A)
-> List (Fin (k (length xs)) × A)
go k i [] = []
go k i (x ∷ xs) = (i , x) ∷ go (k ° suc) {!!} xs
The type of the new hole is {n : ?} → Fin (k (suc (suc n)))
. We can fill it with i
, but i
must grow at each recursive call. However suc
and k
doesn't commute, so suc i
is Fin (suc (k (suc (_n_65 k i x xs))))
. So we add another argument that suc
s under k
, and the final definition is
enumerate-Fin : ? {α} {A : Set α} -> (xs : List A) -> List (Fin (length xs) × A)
enumerate-Fin = go id suc zero where
go : ? {α} {A : Set α}
-> (k : ? -> ?)
-> (? {n} -> Fin (k n) -> Fin (k (suc n)))
-> (? {n} -> Fin (k (suc n)))
-> (xs : List A)
-> List (Fin (k (length xs)) × A)
go k s i [] = []
go k s i (x ∷ xs) = (i , x) ∷ go (k ° suc) s (s i) xs
which works, because s : {n : ?} → Fin (k n) → Fin (k (suc n))
can be treated as {n : ?} → Fin (k (suc n)) → Fin (k (suc (suc n)))
.
A test: C-c C-n
enumerate-Fin (1 ∷ 3 ∷ 2 ∷ 5 ∷ [])
gives
(zero , 1) ∷
(suc zero , 3) ∷
(suc (suc zero) , 2) ∷ (suc (suc (suc zero)) , 5) ∷ []
Now note that in enumerate-Fin
k
always follows Fin
in the types. Hence we can abstract Fin ° k
and get a generic version of the function that works with both ?
and Fin
:
genumerate : ? {α β} {A : Set α}
-> (B : ? -> Set β)
-> (? {n} -> B n -> B (suc n))
-> (? {n} -> B (suc n))
-> (xs : List A)
-> List (B (length xs) × A)
genumerate B s i [] = []
genumerate B s i (x ∷ xs) = (i , x) ∷ genumerate (B ° suc) s (s i) xs
enumerate-? : ? {α} {A : Set α} -> List A -> List (? × A)
enumerate-? = genumerate _ suc 0
enumerate-Fin : ? {α} {A : Set α} -> (xs : List A) -> List (Fin (length xs) × A)
enumerate-Fin = genumerate Fin suc zero