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 = ?