Listas de números

Generalizando a definição de pares, podemos descrever o tipo de listas de números assim: “Uma lista ou é a lista vazia ou então um conjunto de um elemento e outra Lista", esse tipo não é composto de um head e uma tail.

type List (t) {
  nil
  cons (head: t) (tail: List t)
}

Como vamos tratar de apenas um tipo, é interessante reescrever o tipo de lista para um definido, o escolhido foi o Nat:

type NatList {
  nil
  cons (head: Nat) (tail: NatList)
}

ou

type NatList {
   List Nat
}

Podemos perceber que em ambas as notações, há um head e um tail, sendo que o head recebe um elemento do tipo Nat e a tail recebe uma lista do tipo Nat.

Por exemplo, uma lista de três números naturais 1n, 2n e 3n seria escrita da seguinte forma:

[1n, 2n, 3n]

O Kind, entretanto, lê de outra forma:

[1n, [2n, 3n]]

onde o 1n é a head e o [2n, 3n] é a tail. Da mesma forma, ao olhar para uma lista de 4 elementos [1n, 2n, 3n, 4n], agora veremos da seguinte forma:

[1n, [2n, [3n, 4n]]]

A lista possui o head 1n e a tail [2n, [3n, 4n]], que, por sua vez, possui a head 2n e a tail [3n, 4n] que também possui sua head 3n e sua tail 4n.

Pode parecer assustador, mas é um monstro amigável:

img

[fonte da imagem: http://learnyouahaskell.com/starting-out]

Repeat

A função repeat recebe um número n e um valor, retornando uma lista de tamanho n onde todos os elementos é o valor declarado.

// Exemplo: (Repeat 3 Bool.true) -> [True, True, True]
Repeat (x: Nat) (count: Nat) : List Nat
Repeat x Nat.zero            = [] 
Repeat x (Nat.succ count)    = List.cons Nat x (Repeat count x)

Length

A função length calcula o tamanho da lista

// Exemplo: (Length [1,2,3]) -> 3
Length (xs: List Nat) : Nat
Length List.nil              = 0n
Length (List.cons head tail) = (Nat.succ (Length tail))

Concat

A função concat concatena (anexa) duas listas.

Concat (xs: List Nat) (ys: List Nat) : List Nat
Concat (List.nil)            ys = ys
Concat (List.cons head tail) ys = List.cons Nat head (Concat tail ys)

Head e Tail

A função head retorna o primeiro elemento (a “cabeça”) da list, enquanto tail retorna tudo menos o primeiro elemento (a “cauda”). Claro, o lista vazia não tem primeiro elemento, então devemos tratar esse caso com um tipo Maybe, recebendo um Maybe.none caso a lista seja vazia ou um Maybe.some caso tenha um valor.

// Exemplo: (Head 0n [1n,2n,3n]) -> 1n
Head (default: Nat) (xs: List Nat) :  Nat
Head default (List.nil)            = default
Head default (List.cons head tail) = head
// Exemplo: (Tail Nat [1,2,3]) -> [2,3]
Tail (xs: List Nat)        : List Nat
Tail (List.nil)            = []
Tail (List.cons head tail) = tail
Test_head1 : Equal Nat (Head 0n [1n,2n,3n]) 1n
Test_head1 = Equal.refl
Test_head2 : Equal Nat (Head 0n List.nil) 0n
Test_head2 = Equal.refl
Test_head3 : Equal (List Nat) (Tail [1n, 2n, 3n]) [2n, 3n]
Test_head3 = Equal.refl

Exercícios

List_funs

Complete as definições de Nonzeros, Oddmembers e Countoddmembers abaixo. Dê uma olhada nos testes para entender o que essas funções devem fazer.

Nonzeros (xs: List Nat) : List Nat
Nonzeros xs = ?
Test_nonzeros : Equal (List Nat) (Nonzeros [0n,1n,0n,2n,3n,0n,0n]) [1n,2n,3n]
Test_nonzeros = ?
Oddmembers (xs: List Nat) : List Nat
Oddmembers xs = ?
Test_oddmembers : Equal (List Nat) (Oddmembers [0n,1n,0n,2n,3n,0n,0n]) [1n,3n]
Test_oddmembers = ?
CountOddMembers (xs: List Nat)  : Nat
CountOddMembers xs = ?
Test_countoddmembers1 : Equal Nat (CountOddMembers [1n,0n,3n,1n,4n,5n]) 4n
Test_countoddmembers1 = ?

Alternate

Complete a definição de alternate, que “compacta” duas listas em uma, alternando entre os elementos tomados da primeira lista e elementos da segunda. Veja os testes abaixo para mais exemplos específicos.

Alternate (xs: List Nat) (ys: List Nat) : List Nat
Alternate xs ys = ?
Test_alternate1 : Equal (List Nat) (Alternate [1n,2n,3n] [4n,5n,6n]) [1n,4n,2n,5n,3n,6n]
Test_alternate1 = ?
Test_alternate2 : Equal (List Nat) (Alternate [1n] [4n,5n,6n]) [1n,4n,5n,6n]
Test_alternate2 = ?
Test_alternate3 : Equal (List Nat) (Alternate  [1n,2n,3n] [4n]) [1n,4n,2n,3n]
Test_alternate3 = ? 
Test_alternate4 : Equal (List Nat) (Alternate [] [20n,30n]) [20n,30n]
Test_alternate4 = ?

Functions

Complete as seguintes definições para as funções count, sum, add, e member das listas de naturais

Count (v: Nat) (xs: List Nat) : Nat
Count v xs = ?
Test_count1 : Equal Nat (Count 1n [1n,2n,3n,1n,4n,1n]) 3n
Test_count1 = ?
Test_count2 : Equal Nat (Count 6n [1n,2n,3n,1n,4n,1n]) 0n
Test_count2 = ?
Sum (xs: List Nat) (ys: List Nat) : List Nat
Sum xs ys = ?
Test_sum1 : Equal Nat (Count 1n (Sum [1n,2n,3n] [1n,4n,1n])) 3n
Test_sum1 = ?
Add (n: Nat) (xs: List Nat) : List Nat
Add n xs = ?
Test_add1 : Equal Nat (Count 1n (Add 1n [1n,4n,1n])) 3n
Test_add1 = ?
Test_add2 : Equal Nat (Count 5n (Add 1n [1n,4n,1n])) 0n
Test_add2 = ?
Member (v: Nat) (xs: List Nat) : Bool
Member v xs = ?
Test_member1 : Equal Bool (Member 1n [1n,4n,1n]) Bool.true
Test_member1 = ?
Test_member2 : Equal Bool (Member 2n [1n,4n,1n]) Bool.false
Test_member2 = ?

More_functions

Aqui estão mais algumas funções de List Nat para você praticar. Quando remove_one é aplicado a uma lista sem o número a ser removido, ele deve retornar a mesma lista inalterada

Remove_one (v: Nat) (xs: List Nat) : List Nat
Remove_one v xs = ?
Test_remove_one1 : Equal Nat (Count 5n (Remove_one 5n [2n,1n,5n,4n,1n])) 0n
Test_remove_one1 = ?
Test_remove_one2 : Equal Nat (Count 5n (Remove_one 5n [2n,1n,4n,1n])) 0n
Test_remove_one2 = ?
Test_remove_one3 : Equal Nat (Count 4n (Remove_one 5n [2n,1n,5n,4n,1n,4n])) 2n
Test_remove_one3 = ?
Test_remove_one4 : Equal Nat (Count 5n (Remove_one 5n [2n,1n,5n,4n,5n,1n,4n])) 1n
Test_remove_one4 = ?
Remove_all (v: Nat) (xs: List Nat) : List Nat
Remove_all v xs = ?
Test_remove_all1  : Equal Nat (Count 5n (Remove_all 5n [2n,1n,5n,4n,1n])) 0n
Test_remove_all1  = ?
Test_remove_all2  : Equal Nat (Count 5n (Remove_all 5n [2n,1n,4n,1n])) 0n
Test_remove_all2  = ?
Test_remove_all3  : Equal Nat (Count 4n (Remove_all 5n [2n,1n,5n,4n,1n,4n])) 2n
Test_remove_all3  = ?
Test_remove_all4  : Equal Nat (Count 5n (Remove_all 5n [2n,1n,5n,4n,5n,1n,4n,5n,1n,4n])) 0n
Test_remove_all4  = ?
Subset (xs: List Nat) (ys: List Nat)  : Bool
Subset xs ys = ?
Test_subset1 : Equal Bool (Subset [1n,2n] [2n,1n,4n,1n]) Bool.true
Test_subset1 = ?
Test_subset2 : Equal Bool (Subset [1n,2n,2n] [2n,1n,4n,1n]) Bool.false
Test_subset2 = ?

Theorem

Anote um teorema interessante, envolvendo as funções count e add e prove-o. Note que, como este problema é um pouco aberto, é possível que você venha com um teorema que seja verdadeiro, mas cuja prova requer técnicas que você ainda não aprendeu. Sinta-se à vontade para pedir ajuda se ficar preso!

Theorem : ?