Maybe
Suppose we want to write a function that returns the nth number of a list. We then define a number that is applied to a list of naturals and returns the number that occupies that position. Therefore, we need to define a number to be returned if the number is greater than the size of the list.
Nth_bad (n: Nat) (xs: List Nat) : Nat
Nth_bad n List.nil = 42n // arbitrary value
Nth_bad Nat.zero (List.cons head tail) = head
Nth_bad (Nat.succ n) (List.cons head tail) = Nth_bad n tail
This solution is not so good: if nth_bad returns 0, we cannot tell if that value actually appears in the input without further processing. A better alternative is to change the return type of nth_bad to include an error value as a possible result.
We call this type Maybe
, because it may or may not have something; if it has, it is a Maybe.some
of that something, if it does not have, it is a Maybe.none
.
type Maybe (t) {
none
some (value: t)
}
We can then change the above definition of nth_bad to return None when the list is too short and Some when the list has enough members and appears at the position n. We call this new function nth_error to indicate that it may result in an error.
This proof also serves to introduce us to another feature of Kind, conditional expressions, the if
and else
.
Nth_error (n: Nat) (xs: List Nat) : Maybe Nat
Nth_error n List.nil = Maybe.none
Nth_error n (List.cons head tail) =
let ind = Nth_error (Pred n) tail
Bool.if (Eql n 0n) (Maybe.some Nat head) (ind)
Test_nth_error1 : Equal (Nth_error 0n [4n,5n,6n,7n]) (Maybe.some 4n)
Test_nth_error1 = Equal.refl
Test_nth_error2 : Equal (Nth_error 3n [4n,5n,6n,7n]) (Maybe.some 7n)
Test_nth_error2 = Equal.refl
Test_nth_error3 : Equal (Nth_error 9n [4n,5n,6n,7n]) Maybe.none
Test_nth_error3 = Equal.refl
Extract (d: Nat) (o: Maybe Nat) : Nat
Extract d (Maybe.some k) = k
Extract d (Maybe.none) = d
Head_error
Using the same idea, correct the Head
function from before so that we don't have to pass a default element for the case List.nil
.
Head_error (xs: List Nat) : Maybe Nat
Head_error xs = ?
Test_head_error1 : Equal (Head_error List.nil) Maybe.none
Test_head_error1 = ?
Test_head_error2 : Equal (Head_error [1n]) (Maybe.some Nat 1n)
Test_head_error2 = ?
Test_head_error3 : Equal (Head_error [5n,6n]) (Maybe.some Nat 5n)
Test_head_error3 = ?
Opcional: Extract_head
This exercise relates your new Head_error
to the old Head
.
Extract_head (l: List Nat) (default: Nat) : Equal Nat (Head default l) (Extract default (Head_error l))
Extract_head l default = ?