Docsity
Docsity

Prepare-se para as provas
Prepare-se para as provas

Estude fácil! Tem muito documento disponível na Docsity


Ganhe pontos para baixar
Ganhe pontos para baixar

Ganhe pontos ajudando outros esrudantes ou compre um plano Premium


Guias e Dicas
Guias e Dicas


Introdução às Listas em CLEAN: Estrutura e Funções, Notas de estudo de Informática

Neste documento, aprenderemos sobre a linguagem clean e suas funções para trabalhar com listas. A estrutura de uma lista em clean é [c:r], onde c é a cabeça e r o resto da lista. A cabeça é o primeiro elemento, e a cauda é a lista que contém todos os elementos da lista, exceto a cabeça. Existem diferentes tipos de listas, como listas de reais, strings, caracteres, listas de listas, e listas definidas por um intervalo. A compreensão de listas em clean é uma notação para criar listas com base em uma regra. Além disco, aprenderemos a definir funções com listas e as funções primitivas existentes em clean para manipula-las.

Tipologia: Notas de estudo

Antes de 2010

Compartilhado em 18/08/2008

tais-ferreira-1
tais-ferreira-1 🇧🇷

5 documentos

1 / 32

Toggle sidebar

Esta página não é visível na pré-visualização

Não perca as partes importantes!

bg1
Capítulo 5 – Listas
Freqüentemente em programação nos deparamos com situações onde
desejamos modelar uma coleção de objetos. Vejamos dois exemplos:
Um programa de computador pode automatizar o processo de se verificar se
uma dada pessoa possui um telefone. Neste caso, dado o nome da pessoa e
uma lista telefônica, o programa poderia devolver o número do telefone desta
pessoa, caso tenha, ou devolver a informação de que a mesma não possui
telefone. Um programa como este deve, portanto, modelar nomes, números e
uma lista telefônica. Uma lista telefônica pode ser vista como uma coleção de
pares formados por nomes e números.
Quando fazemos compras em um supermercado e vamos até o caixa para
realizar o pagamento, presenciamos o seguinte procedimento: cada
mercadoria que colocamos no carrinho é passada num scanner. Após todas as
mercadorias serem passadas pode-se ter o valor total a ser pago. Através de
um scanner, um dispositivo usado pelo caixa para fazer a leitura do código de
barras presentes na mercadoria, tem-se automaticamente a descrição em um
monitor de vídeo o nome da mercadoria e o seu preço. Isto nos faz pensar que
este processo utiliza um programa que dada a mercadoria, identificada por seu
código de barras, devolve o nome da mercadoria e o seu valor.
As listas em CLEAN representam coleções de objetos de um determinado tipo
e, portanto, é uma ferramenta bastante útil quando desejamos modelar coleções
de objetos.
As listas são importantes para a programação funcional assim como a teoria de
conjuntos é importante para muitos dos ramos da matemática.
A linguagem CLEAN possui várias funções que trabalham com listas, não
sendo necessário, portanto, que recriemos todas elas. Estas funções básicas,
denominadas de primitivas, estão no módulo StdList fornecido juntamente com o
CLEAN. Elas estão prontas para serem utilizadas quando você carrega o módulo
StdEnv digitando import StdEnv logo após o nome do módulo o qual deverá
possuir o mesmo nome do arquivo .icl criado para armazenar seus programas.
5.1 – Conceitos Básicos Relacionados a Listas
1 - Lista: uma lista é uma seqüência finita ou não de elementos colocados entre
colchetes e separados por vírgula. Os elementos de uma lista devem ser do
mesmo tipo.Uma Lista em CLEAN possui a seguinte estrutura: [c:r], onde c é a
cabeça da lista (o primeiro elemento dela) e r o resto da lista (sua calda).
Uma lista possui uma cabeça e uma cauda.
A cabeça da lista é seu primeiro elemento.
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d
pf1e
pf1f
pf20

Pré-visualização parcial do texto

Baixe Introdução às Listas em CLEAN: Estrutura e Funções e outras Notas de estudo em PDF para Informática, somente na Docsity!

Capítulo 5 – Listas

Freqüentemente em programação nos deparamos com situações onde desejamos modelar uma coleção de objetos. Vejamos dois exemplos:

  • Um programa de computador pode automatizar o processo de se verificar se uma dada pessoa possui um telefone. Neste caso, dado o nome da pessoa e uma lista telefônica, o programa poderia devolver o número do telefone desta pessoa, caso tenha, ou devolver a informação de que a mesma não possui telefone. Um programa como este deve, portanto, modelar nomes, números e uma lista telefônica. Uma lista telefônica pode ser vista como uma coleção de pares formados por nomes e números.
  • Quando fazemos compras em um supermercado e vamos até o caixa para realizar o pagamento, presenciamos o seguinte procedimento: cada mercadoria que colocamos no carrinho é passada num scanner. Após todas as mercadorias serem passadas pode-se ter o valor total a ser pago. Através de um scanner, um dispositivo usado pelo caixa para fazer a leitura do código de barras presentes na mercadoria, tem-se automaticamente a descrição em um monitor de vídeo o nome da mercadoria e o seu preço. Isto nos faz pensar que este processo utiliza um programa que dada a mercadoria, identificada por seu código de barras, devolve o nome da mercadoria e o seu valor.

As listas em CLEAN representam coleções de objetos de um determinado tipo e, portanto, é uma ferramenta bastante útil quando desejamos modelar coleções de objetos.

As listas são importantes para a programação funcional assim como a teoria de conjuntos é importante para muitos dos ramos da matemática.

A linguagem CLEAN possui várias funções que trabalham com listas, não sendo necessário, portanto, que recriemos todas elas. Estas funções básicas, denominadas de primitivas , estão no módulo StdList fornecido juntamente com o CLEAN. Elas estão prontas para serem utilizadas quando você carrega o módulo StdEnv digitando import StdEnv logo após o nome do módulo o qual deverá possuir o mesmo nome do arquivo .icl criado para armazenar seus programas.

5.1 – Conceitos Básicos Relacionados a Listas

1 - Lista : uma lista é uma seqüência finita ou não de elementos colocados entre colchetes e separados por vírgula. Os elementos de uma lista devem ser do mesmo tipo.Uma Lista em CLEAN possui a seguinte estrutura: [c:r], onde c é a cabeça da lista (o primeiro elemento dela) e r o resto da lista (sua calda).

  • Uma lista possui uma cabeça e uma cauda.
  • A cabeça da lista é seu primeiro elemento.
  • A cauda de uma lista é uma lista que contém todos os elementos da lista com exceção da cabeça.

2 - Lista vazia : uma lista vazia é representada por [ ] , ou seja, o abrir e fechar de colchetes com tantos espaços em branco internamente quanto se deseje.

Exemplos de listas finitas:

  • lista de inteiros: [1,2,3,4]

[ 1 , 2,3,4 ] CAUDA DA LISTA = [ 2 , 3 , 4 ]

CABEÇA

DA LISTA

Comparando a lista [1,2,3,4] com [c:r] temos que: c = 1 e r = [2,3,4]

  • lista de reais: [1.0,2.0,3.0,4.0] onde c = 1.0 e r = [2.0,3.0,4.0]
  • lista de strings: ["a","b","c"] onde c = "a" e r = ["b","c"]
  • lista de caracteres: ['a','b','c'] onde c = 'a' e r = ['b','c']
  • lista de listas: [ ['a','b'], ['d','e']] onde c =['a','b'] e r = [['d','e']]

CAUDA DA LISTA = [['d','e']]

CABEÇA DA

LISTA = ['a','b']

  • lista de tuplas : [(1,2), (3,4), (5,6)] onde c=(1,2) e r = [(3,4), (5,6)] obs.: Se você não conhece o tipo tupla, dê uma olhada no capítulo 3 deste mesmo livro. Observação: Listas que possuem os mesmos elementos, mas em ordem diferente, são listas diferentes: Exemplo: A lista [1,2,3] é diferente da lista [2,1,3].

3 - Listas Definidas por Intervalo : uma forma diferente de se construir uma lista faz uso de uma notação de intervalo. A notação de intervalo é definida por duas expressões numéricas separadas por dois pontos delimitadas por colchetes.

Exemplos de listas de inteiros definidas por um intervalo

  • [1..5] denota a lista [1,2,3,4,5]. A forma [a..b] permite especificar a lista de números numa ordem crescente de a até b com os limites a e b incluídos. Se a for maior que b , a notação [ a..b] denota uma lista vazia.
  • [1,3..7] especifica a lista [1,3,5,7]. Perceba que ao especificarmos o segundo elemento da lista estabeleceu se uma regra, um degrau, para

Entendendo o programa: 1- Criamos um função chamada patternMatch cujo argumento é uma lista r que possui três elementos [x,y,z]. A forma de CLEAN expressar o que foi dito é: r =: [x,y,z]. O operador =: atribui a r a estrutura da lista [x,y,z]. 2- Ao executarmos esta função: Start = patternMatch [2,4,6] , pelo pattern match de r=: [x,y,z] com a lista [2,4,6] , teremos que x=2 , y=4 e z=6 , assim, obtemos o resultado de yz = 64 = 24**.

Assim, para separar a cabeça e a cauda de uma lista, em CLEAN, basta comparar, fazer o pattern match da lista desejada com [c:r]. Desta forma, dado uma lista list = [1,2,3,4,5] , se a compararmos com a definição genérica de uma lista [c:r] , para que [1,2,3,4,5] seja igual a [c:r], concluímos que c = 1 e r = [2,3,4,5]. Como list = [1,2,3,4,5] e list = [c:r] , conclui-se, pelo pattern match , que c = 1 e r = [2,3,4,5].

5.2 Declarando o Tipo de Uma Lista

Como já vimos no capítulo INTRODUÇÃO, CLEAN é uma linguagem fortemente tipada, sendo esta uma característica importante quando se deseja programar em uma linguagem que evite efeitos colaterais indesejados. Você deverá declarar o tipo de uma função quando desejar que ela só aceite como argumento e resposta os tipos de dados que você estipulou. Isto evita que um programa seja compilado e algum programador menos avisado tente utilizar sua função com tipos de dados diferentes. Se você não declarar o tipo de sua função, o CLEAN deduzirá por si só. Neste caso, o mesmo só verificará se você não está utilizando a função a cada momento com um tipo diferente. Assim, se você utilizar uma vez argumentos inteiros para uma determinada função f você não poderá utilizar, em um mesmo programa, no mesmo módulo, argumentos que não sejam inteiros para f.

Quando você for declarar o tipo de uma função cujos argumentos utilizem o tipo lista, proceda de forma similar a aquela mostrada nos exemplos mostrados a seguir.

Exemplo 1: Listas de caracteres

Declaração de tipo de uma função f que aceita como argumento de entrada uma lista de caracteres e devolve como resposta uma lista de caracteres.

f :: [Char] -> [Char]

Exemplo 2: Listas de inteiros e reais

Declaração de tipo de uma função f que aceita como argumentos de entrada uma lista de inteiros e uma lista de reais e devolve como resposta uma lista de inteiros.

f :: [Int] [Real] -> [Int]

Exemplo 3: Listas de strings

Declaração de tipo de uma função f que aceita como argumento de entrada uma lista de strings e devolve como resposta um string.

f :: [String] -> String ou^1 f :: [{#CHAR}] -> {#Char}

5.3 Compreensão de Listas – Notação Zermelo-Frankel

Esta é sem dúvida alguma a ferramenta mais eficiente desta linguagem. Além de permitir a criação de listas de elementos gerados por funções extremamente complexas, de uma forma clara e simples, o código gerado é compacto e veloz.

A Notação Zermelo-Frankel Na teoria de conjuntos a seguinte notação é comumente utilizada na definição de conjuntos:

S = { x^3 | x ∈Ν }

A expressão descrita anteriormente é normalmente denominada de uma compreensão de conjunto. Ela deve ser lida da seguinte forma: S é o conjunto é

(^1) Ver o livro sobre vetores para ver porque o Tipo String pode ser declarado como {#Char}

como o símbolo ∈ não está disponível no teclado, indica-se pertinência utilizando- se o sinal de menor ( < ) seguido do sinal de menos ( - ). Uma expressão x <− xs é denominado de gerador.

Tal como na Matemática, CLEAN permite que se utilizem condições para filtrar (eliminar) elementos do contradomínio. Vamos ver um exemplo ilustrativo:

Exemplo: vamos gerar uma lista cujos elementos sejam o quadrado dos números pares que estão no intervalo de 1 a 10.

Da matemática temos: S = { x^2 | 1 =< x >= 10 & x é par } Em CLEAN^2 temos: S = [xx \ x <-[1..10] | isEven x] Obs*. A função isEven é uma primitiva do CLEAN que testa se um valor é ou não par.

INTERVALOS REAIS

Muitas vezes precisamos gerar intervalos de números reais em nossas funções, como é o caso do exemplo de integração numérica que mostraremos logo a seguir. Antes do exemplo, vamos ver como tratar listas com intervalos reais. Os intervalos de reais podem ser obtidos de duas maneiras:

  1. Explicitando todos os elementos da lista: [sin x \ x <− [4.5, 2.3, 1.0]]
  2. Utilizando a notação de intervalo [a0,a1..an]. Fornece-se o primeiro (a0), o segundo (a1) e o último (an) elementos da lista com o segundo elemento separado do último elemento por dois pontos (..). A diferença entre o segundo e o primeiro elemento fornece o passo ou o degrau, isto é, a diferença entre os elementos sucessivos conforme salientamos anteriormente. Assim, com esta notação, podemos definir a seguinte lista: [sin x\x <− [0.0,0.1..3.1416]. Esta lista será formada por elementos correspondentes aos senos dos valores no intervalo especificado. Nós utilizaremos a segunda forma no programa exemplo para realizar a integração numérica pelo método dos trapézios^3. Para aqueles que conhecem os processos de integração, este exemplo é bastante atrativo. No método dos trapézios, o valor aproximado da integral é dado pela seguinte fórmula:

∈ + +×⋅⋅−

≈ × + × +

[ , 2 ]

x a ha hbh

b

a

fnxdx fna fnb fnx

Veja como é simples implementar esta complexa função, em CLEAN, utilizando a notação Zermelo-Frankel para listas.

(^2) Observe o quanto aderente, o quão parecido, é a notação em CLEAN à definição

matemática.

(^3) Se você não tem ainda algum conhecimento sobre integrais, você pode saltar este exemplo.

Onde: fn = função escolhida para integrar a = início do intervalo de integração b = fim do intervalo de integração h = incremento

Observe que o programa expressa de forma sucinta a fórmula matemática do método dos trapézios. O valor na parte inferior da figura mostra o resultado da integral da função co-seno para o intervalo de 0.0 a 5.231 com incremento igual a 0.001.

UTILIZANDO MAIS DE UM GERADOR AO MESMO TEMPO Numa compreensão de listas, após as duas barras invertidas ( \ ) pode aparecer mais de um gerador separados por uma vírgula. Quando isto ocorre temos uma combinação ortogonal de geradores. Ao se utilizar uma combinação ortogonal de geradores, a expressão colocada na frente das duas barras invertidas é calculada para toda possível combinação das variáveis correspondentes. O exemplo, a seguir, torna mais claro o que foi dito:

Este programa devolve a lista [(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)] , ou seja, ele pega o primeiro elemento do primeiro gerador ( x<-[1..3] ) e devolve todas as combinações com os elementos do segundo gerador ( y<-[4..6] ), ou seja: (1,4),(1,5) e (1,6) , depois pega o segundo elemento do primeiro gerador e devolve todas as combinações com os elementos do segundo gerador, ou seja: (2,4),(2,5) e (2,6) , o processo continua até que o programa tenha obtido todas as combinações possíveis de elementos do primeiro gerador como elementos do

Assim, quando a menor lista é totalmente percorrida, todos os geradores combinados com & param de gerar elementos.

Podemos estabelecer condições para os valores a serem gerados por uma combinação de geradores. A condição, mais uma vez, deve ser separada dos geradores por uma barra vertical. O programa devolve a lista [(2,1),(2,2),(4,1),(4,2),(4,3),(4,4)]. Observe que a visibilidade da variável x (denominada de escopo de x ) não se restringe somente ao lado esquerdo da compreensão. Ela também pode ser manipulada no lado direito do gerador introduzindo x. Entretanto y não pode ser utilizada nos geradores precedendo-a, isto é, y pode somente ser usada em (x,y) e na condição. O símbolo <− que define a pertinência é especialmente utilizado na compreensão de listas e não constitui um operador.

5.4 Definindo Funções com Listas

Vamos mostrar como projetar e implementar funções em CLEAN que trabalhem com listas, e, posteriormente, vamos apresentar as funções primitivas existentes no CLEAN criadas para esta finalidade. Vamos fazer isto através de vários exemplos que serão mostrados a seguir. Não declararemos o tipo de cada função aqui criada devido as mesmas trabalharem com vários tipos diferentes. Nossa preocupação maior, neste momento, é mostrar como manipular listas em CLEAN. Não se esqueça de criar um arquivo .icl e um módulo de execução para você testar as funções apresentadas. Crie, por exemplo um arquivo com o nome listas.icl e digite o seguinte cabeçalho:

Como você vai testar várias funções, não se esqueça que cada módulo de execução só pode ter um Start ativo ao mesmo tempo^4. Se você tiver mais que um, coloque todos como comentário e deixe apenas um ativo.

Exemplo:

Apenas um Start

Obs. : // no início da linha indica que a mesma é um comentário

EXEMPLO: vamos construir uma função em CLEAN que devolve a cabeça de uma lista. Vamos dar a ela o nome de car.

Função = car | Argumento = uma lista | Formato = car x

A figura a seguir descreve um programa ilustrando a criação e o uso da função car. O valor devolvido decorrente da execução do programa aparece na parte inferior desta figura.

Observe que na linha quatro do programa está a definição da função car. Assim ao digitar esta linha no ambiente Clean criamos a função car. O argumento de car é [c:r]. O argumento está entre colchetes para indicar que o mesmo deve ser uma

(^4) Na realidade pode-se ter mais de um Start, mas, como Start é uma função, todos os Starts deverão possuir o

mesmo tipo de dados com resultado, e, nestes casos, o primeiro Start encontrado será o avaliado por CLEAN.

Na linha quatro do programa aparece a definição da função cadr que tem como argumento uma lista [c:r]. A resposta é o car (a cabeça) da lista r que é a cauda da lista dada [c:r]. O cdr da lista [1,2,3] é a lista de inteiros [2,3] que corresponde à cauda da lista [1,2,3]. A cabeça da cauda [2,3], obtida usando-se a função car , corresponde ao inteiro 2 que aparece na parte inferior da figura (resposta de cadr de [1,2,3] ).

EXEMPLO: vamos criar uma função que devolve a cauda da cauda de uma lista. Vamos dar a ela o nome de de cddr.

Função = cddr | Argumento = uma lista | Formato = cddr x

A figura a seguir descreve um programa ilustrando a criação e o uso da função cddr. O valor devolvido decorrente da execução do programa aparece na parte inferior desta figura.

Na linha quatro do programa aparece a definição da função cddr que tem como argumento uma lista [c:r]. A resposta a esta função é o cdr da lista r que é a cauda da lista de entrada [c:r]. A cauda da cauda da lista [1,2,3] é a lista de inteiros [3] que aparece como resposta na parte inferior da figura.

Outras funções para trabalhar com cabeça e cauda de listas:

caar [c:r] = car c - Devolve a cabeça da cabeça de uma lista (neste caso a cabeça da lista tem que ser uma lista cadddr [c:r] = car (cdr (cdr r)) - Devolve a cabeça da cauda da cauda da cauda de uma lista

EXEMPLO: vamos criar no CLEAN uma função que pega um elemento x e o coloca na cabeça da lista y. Vamos dar a esta função o nome de consLista.

Função = consLista x y | Argumento = duas listas | Formato = consLista x y

Criando a função consLista.

Para criá-la, digite no ambiente do CLEAN consLista x y = [x:y] Se digitarmos: Start = consLista 1 [2,3,4,5] Teremos como resposta [1, 2, 3, 4, 5]

Observe que é relativamente simples criar algumas funções em CLEAN e utilizá- las na implementação de outras funções. CLEAN já possui várias funções que trabalham com listas. Como exemplo podemos citar a função hd^5 (que representa um acrônimo para a palavra head em inglês que traduzimos para cabeça) e a função tl^6 (que representa um acrônimo para a palavra tail em inglês que traduzimos como cauda).

EXEMPLO: Suponha que queiramos definir uma função somaLista que some todos os elementos de uma lista de inteiros. O seu tipo seria declarado como segue.

somaLista:: [Int] -> Int

Para uma lista com um número pequeno de elementos poderíamos defini-la da seguinte forma:

somaLista [x,y,z] = x+y+z

(^5) Equivalente à função car criada anteriormente (^6) Equivalente à função cadr criada por nós

  • Projeto:
  • caso base: dobrar todos os elementos de uma lista [ ] retorna [ ]
  • caso indutivo: multiplicar a cabeça da lista por 2 e junta-la(cons) a lista da

cauda dobrada.

  • Implementação: dobro :: [Int] -> [Int] dobro [] = [] dobro [x:xs] = [(2*x) : dobro xs]
  • Depurando ( trace ): dobro [1,9,37] = dobro [1:[9:[37:[]]]] => [12:[dobro [9:[37:[]]]] => [2:[dobro [9:[37:[]]]]] => [2:[92:[dobro [37:[]]]]] => [2:[18:[dobro [37:[]]]]] => [2:[18:[37*2:[dobro []]]]] => [2:[18:[74:[dobro []]]]] => [2:[18:[74:[]]]] = [2,18,74]

EXEMPLO: definir uma função que calcule o tamanho de uma lista de inteiros.

  • Tipo da função: comp :: [Int] -> Int
  • Projeto:
  • caso base : o comprimento de uma lista vazia é 0.
  • caso indutivo : o comprimento de uma lista [x:y] é um (1) + comprimento da lista y
  • Implementação:

comp :: [Int] -> Int comp [] = 0 comp [x:y] = 1 + comp y

EXEMPLO: definição de ++ para listas de inteiros.

  • Tipo : concatena :: [Int] [Int] -> [Int]
  • Projeto: Esta é mais difícil de projetar porque ela apresenta duas listas como argumentos. Devemos tentar indução na primeira lista, na segunda lista ou em ambas?

Para fazer recursão em duas listas temos quatro casos que correspondem a combinações de casos base e indutivo para cada lista:

[ ] ++ [ ] =... [ ] ++ [y:ys] =... [x:xs] ++ [ ] =... [x:xs] ++ [y:ys] =...

Se começarmos assim poderemos encontrar algumas redundâncias e eliminá-las. Os dois primeiros casos não precisam ser separados. A seguinte regra os cobre:

[ ] ++ ys = ys

A terceira e a quarta regra podem também ser combinadas:

[x:xs] ++ ys = [x : [xs++ys]]

Desta forma apenas recursão sobre a primeira lista é suficiente para definir esta função em particular.

EXEMPLO: a ordenação por Inserção. Devemos projetar uma função que ordene uma lista de inteiros em ordem crescente. Esta função terá o seguinte tipo:

ordIns :: [Int] -> [Int]

Um exemplo de uso: ordIns [7, 3, 9, 2] deve gerar [2, 3, 7, 9]

Como em todos os exemplos anteriores, nossa primeira intuição conduz a dois casos:

ordIns [] =... ordIns [x:xs] =...

O primeiro caso é fácil desde que a lista vazia é trivialmente ordenada. Assim sendo temos que:

ordIns [ ] = [ ]

Para listas não vazias nós temos acesso direto à cabeça x e à cauda xs. Por exemplo:

insere x [] = [x]

Se a lista não é vazia, nós temos acesso direto a sua cabeça. Nós podemos perguntar: "x pertence antes ou após a cabeça da lista?"

  • Se x vem antes da cabeça simples acrescente x na frente da lista.
  • Se x vem após a cabeça, nós podemos usar recursividade de cauda para saber onde x deverá ficar. Assim temos que:

insere x [y:ys] | x <= y = [x :[ y : ys]] | otherwise = [y : (insere x ys)]

O casamento de padrões é um meio poderoso para se definir funções em CLEAN. Entretanto, devemos ter em mente que:

  • Padrões não são expressões arbitrárias
  • variáveis não podem ser repetidas no lado esquerdo da definição.

EXEMPLO: findReps [x : x : xs] = [x : findReps xs] é ILEGAL.

EXEMPLO: acha cod ((cod,nome,valor):reste) = (nome, valor) também é ILEGAL.

A solução é usar guardas para testar por igualdade ao invés de esperar que o casamento de padrões faça isto por você.

EXEMPLO:

acha codBarra [(cod, nome, valor) : resto] | codBarra == cod = (nome, valor) |...

Vamos continuar explorando padrões através de mais um exemplo.

EXEMPLO: definindo a função somaPares.

O tipo da função somaPares é dado a seguir.

somaPares :: [(Int,Int)] -> [Int]

Exemplo de uso da função somaPares :

somaPares [(1, 9), (37, 8)] => [10, 45]

O caso base é padrão:

somaPares [] = []

É possível escolher uma variedade de padrões para o caso indutivo. Em geral, é melhor escolher o padrão mais preciso. Vejamos algumas alternativas e a melhor forma a ser usada.

  • Primeira Alternativa:

somaPares1 [p:ps] = [(fst p + snd p) : somaPares1 ps]

O padrão [p:ps] casa-se com qualquer lista não vazia. Os componentes da sua cabeça são extraidos por fst e snd.

  • Segunda Alternativa:

somaPares2 [p:ps] = [(m + n) : somaPares2 ps] where (m, n) = p

Outra vez o padrão [p:ps] casa-se com qualquer lista não vazia, mas os componentes da cabeça são obtidos por casamento de padrões na definição (m,n) = p dentro da cláusula where.

  • A melhor forma :

somaPares [(m,n):ps] = [m+n : somaPares ps]

Aqui, o padrão mais preciso foi usado, conduzindo a uma definição mais simples e clara da função.

CLEAN faz o casamento de padrões numa ordem seqüencial:

  • da esquerda para a direita numa definição
  • de cima para baixo numa seqüência de definição de claúsulas Quando um casamento fracassa, aquela equação é rejeitada e a próxima verificada.Considere a função meuZip definida a seguir.

meuZip [x:xs] [y:ys] = [(x,y) : meuZip xs ys] meuZip xs ys = []