2

I am learning agda and practicing on lists to get a better understanding. Right now I am trying to write functions for list. I am confused on how to return the head and tail of an empty list. Here is my code:

data list (A : Set) : Set where
[]  : list A
_∷_ : A → list A → list A

Null : {A : Set} → (list A) → Bool
Null [] = true
Null (x ∷ a) = false

tail :  {A : Set} → (list A) → A
tail [] = {!!}
tail (x ∷ []) = x  
tail (x ∷ a) = tail a

head : {A : Set} → (list A) →  A
head [] = {!!}
head (x ∷ a) = x

A work around that I found was that instead of returning the first and last members I return a list containing the first and last members which is as follows:

tail :  {A : Set} → (list A) → (list A)
tail [] = []
tail (x ∷ []) = x ∷ []  
tail (x ∷ a) = tail a

head : {A : Set} → (list A) → (list A)
head [] = []
head (x ∷ a) = (x ∷ [])

But I am still confused about how to return the head and tail values. How can I do this?

P.S Not an assignment. Miles ahead of this stuff in class

danny
  • 400
  • 2
  • 18
  • 1
    The empty list does not have head and tail. You can't return things that doesn't exist. – András Kovács Feb 16 '17 at 21:36
  • @AndrásKovács Does this imply that I never write a function like this in agda? Is there a work around to this other than returning a list? – danny Feb 16 '17 at 21:50
  • 3
    in Agda the type of a function is to be taken very literally. An `A -> B` function returns a `B` for each `A`, and it never loops, never throws exception, never does anything other than returning a `B`. If you find that a type doesn't have an implementation, you must change the type. In this case you may have `head : {A : Set} -> list A -> Maybe A`, or use `Vec` from `Data.Vec` which supports `head` and `tail` for nonempty vectors. – András Kovács Feb 16 '17 at 22:26

2 Answers2

4

In Agda, functions are total: if you have head : {A : Set} -> list A -> A, then it will need to be defined over all lists. However, for head [] you can't conjure up an element for some arbitrary type A (imagine head ([] : list Void)...)

The problem is that your type of head promises too much. It is not, in fact, true that you can return the first element of any list; you can only do it for non-empty lists. So you need to change head to either take a separate proof of non-emptiness, or to take a non-empty list as argument:

module SeparateProof where
  open import Data.List
  open import Data.Bool
  open import Data.Unit

  head : {A : Set} → (xs : List A) → {{nonEmpty : T (not (null xs))}} → A
  head [] {{nonEmpty = ()}} -- There's no way to pass a proof of non-emptiness for an empty list!
  head (x ∷ xs) = x

module NonEmptyType where
  open import Data.List.NonEmpty hiding (head)

  head : {A : Set} → List⁺ A → A
  head (x ∷ xs) = x -- This is the only pattern matching a List⁺ A!
Cactus
  • 27,075
  • 9
  • 69
  • 149
0

This is a misnomer, it is last that you wanted not tail, and for the correct tail function, you could just look at drop in Data\List\Base.agda of the standard library:

drop : ∀ {a} {A : Set a} → ℕ → List A → List A
drop zero    xs       = xs
drop (suc n) []       = []
drop (suc n) (x ∷ xs) = drop n xs
--e.g. drop 1
tail : ∀ {a} {A : Set a} → List A → List A
tail []       = []
tail (x ∷ xs) = xs
Gregory Morse
  • 369
  • 2
  • 10