I would like to define a head
function for lists.
In order to avoid trying to compute the head of an empty list one
can either work with vectors of length greater than one (i.e., Vec (suc n)
)
or work with List
s, but pass a proof that the list is non-empty to head
.
(This is what "Dependent Types at Work" calls internal vs external
programming logic, I believe.)
I am interested in the latter approach.
Note that there is a SO answer which addresses this, but I wanted
a minimal approach. (For example, I would prefer not to use Instance Arguments
unless they are required.)
Below is my attempt, but I don't fully understand what is going on.
For example:
- It's not clear why I was able to skip the
head []
case. Obviously it's related to the "proof" I pass in but I would have expected I would need some kind of case with()
in it. - When I type check (C-c C-l) I seem to get two goals as output.
- I would have liked to have seen
tmp2
fail to type check.
Any insight would be very welcome. In particular, what is the "right" way(s) to do what I am trying to do?
data List (A : Set) : Set where
[] : List A
_::_ : A → List A → List A
{-
head1 : {A : Set} → (as : List A) → A
-- As expected, complains about missing case `head1 []`.
head1 (a :: aa) = a
-}
data ⊤ : Set where
tt : ⊤
data ⊥ : Set where
isNonEmpty : {A : Set} → List A → Set
isNonEmpty [] = ⊥
isNonEmpty (_ :: _) = ⊤
head : {A : Set} → (as : List A) → {isNonEmpty as} → A
head (a :: _) = a
-- Define just enough to do some examples
data Nat : Set where
zero : Nat
suc : Nat → Nat
{-# BUILTIN NATURAL Nat #-}
len1 : List Nat
len1 = 17 :: []
tmp : Nat
tmp = head len1
tmp1 : Nat
tmp1 = head len1 { tt }
len0 : List Nat
len0 = []
tmp2 : Nat
tmp2 = head len0