Maybe

Suponha que a gente queira escrever uma função que retorna o enésimo número de uma lista. Nós então definimos um número que é aplicado a uma lista de naturais e então retorna o número que ocupa essa posição. Dessa forma, nós precisamos definir um número para ser retornado caso o número seja maior do que o tamanho da lista.

Nth_bad (n: Nat) (xs: List Nat) : Nat Nth_bad n List.nil = 42n // Valor arbitrário Nth_bad Nat.zero (List.cons head tail) = head Nth_bad (Nat.succ n) (List.cons head tail) = Nth_bad n tail

Esta solução não é tão boa: se nth_bad retornar 0, não podemos dizer se esse valor realmente aparece na entrada sem processamento adicional. Uma alternativa melhor é para alterar o tipo de retorno de nth_bad para incluir um valor de erro como um possível resultado. Chamamos esse tipo Maybe, pois ele pode ou não ter algo, se tiver é um Maybe.some desse algo, se não tiver, é um Maybe.none.

type Maybe (t) { none some (value: t) }
type NatMaybe { none some (value: Nat) }

ou

type NatMaybe { Maybe Nat }

Podemos então alterar a definição acima de nth_bad para retornar None quando a lista for muito curto e Some a quando a lista tem membros suficientes e aparece na posição n. Chamamos essa nova função de nth_error para indicar que pode resultar em um erro.

Essa prova ainda serve pra nos apresentar outro recurso do Kind, expressões condicionais, o if e 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

Usando a mesma ideia, corrija a função Head de antes para que não tenhamos que passar um elemento padrão para o caso 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

Este exercício relaciona sua novo Head_error para o antigo Head.

Extract_head (l: List Nat) (default: Nat) : Equal Nat (Head default l) (Extract default (Head_error l)) Extract_head l default = ?