Paradigmas
Em muitos cursos de Computacao e Engenharia iniciam com paradigma
imperativo.
Exemplo classico da receita de bolo.
1
Paradigma Imperativo
• Descrevo passo a passo o que deve ser feito.
• Infame goto.
• Evoluiu para o procedural e estruturado com if, while, for.
3
Paradigma Imperativo
int pares[10];
for (int i=0; i<10; i++) {
pares[i] = dobro();
}
int dobro () {
static int i = 0;
++i;
return i;
}
4
Problemas
Ao seguir o passo a passo, voce chega no resultado...mas nao tem ideia
de qual sera ele.
Qualquer um pode usar suas variaveis globais e suas funcoes, para o seu
uso intencional ou nao...
5
Orientacao a Objetos
Outro paradigma muito estudado em cursos de Computacao.
Encapsula dados com seus proprios metodos.
Evita que certas informacoes e procedimentos sejam utilizados fora de
seu contexto.
6
Orientacao a Objetos
class Pares {
private int i; // n~ao quero ninguem mudando meu estado
private ArrayList lista;
public Pares() {
i=0;
lista = new ArrayList();
}
public void addOne() {
++i;
lista.add(2*i);
}
public ArrayList get(){
return lista;
}
}
7
Orientacao a Objetos
class Main {
public static void main(String[] args) {
Pares l1 = new Pares();
l1.addOne();
l1.addOne();
l1.addOne();
System.out.println(l1.get());
}
}
8
Problemas
Nos textos didaticos temos exemplos simples e criados para ilustrar
quando faz sentido termos objetos.
Nem sempre isso representa a realidade.
Composicao de funcoes atraves de heranca = bagunca!
10
Problemas
Encapsula codigos imperativos para seguranca e reuso, mas nao evita os
bugs na criacao das classes.
Usa estado intensivamente, incentiva mutabilidade e nao-determinismo.
Difıcil de paralelizar.
11
Efeito colateral
A execucao da instrucao atual depende do estado atual do sistema.
Ex.: dobro() e addOne() vai depender do estado atual de i.
12
Efeito colateral
Eu posso executar a funcao dobro() para o primeiro e o segundo
elemento em paralelo??
13
Paradigma Funcional
• Computacao = avaliacao de composicao de funcoes.
• Evita estados.
• Declarativo.
14
Paradigma Funcional
take 10 [2*i | i <- zplus]
-- pegue 10 elementos da lista formada pelo
-- dobro dos numeros inteiros positivos.
15
Paradigma Funcional
Note que i nao e uma variavel, nao muda de valor, e apenas um sımbolo
da definicao.
16
Funcoes Puras
Linguagens funcionais incentivam (ou obrigam) a criacao de funcoes
puras.
Ao chamar a funcao com o mesmo argumento, sempre tera a mesma
resposta.
Se nao temos efeito colateral...
• ...e o resultado de uma expressao pura nao for utilizado, nao precisa
ser computado.
• ...o programa como um todo pode ser reorganizado e otimizado.
• ...e possıvel computar expressoes em qualquer ordem (ou em
paralelo).
17
Funcoes Puras
double media (int * valores, int n) {
double soma = 0;
int i;
for (i = 0; i < n; i++)
soma_valor(&soma, valores[i]);
return soma / n;
}
void soma_valor (double * soma, int valor) {
soma += valor;
}
18
Programacao sem bugs
A ausencia de estados permite evitar muitos erros de implementacao.
O lema da linguagem Haskell: ”se compilou, o codigo esta correto!”
19
Iteracoes vs Recursoes
Em linguagens funcionais os lacos iterativos sao implementados via
recursao, geralmente levando a um codigo enxuto e declarativo.
20
Iteracoes vs Recursoes
int gcd (int m, int n) {
int r = m % n;
while(r != 0) {
m = n; n = r; r = m%n;
}
return m;
}
21
Avaliacao Preguicosa
Algumas linguagens funcionais implementam o conceito de avaliacao
preguicosa.
Quando uma expressao e gerada, ela gera uma promessa de execucao.
Se e quando necessario, ela e avaliada.
23
Avaliacao Preguicosa
int main () {
int x = 2;
f(x*x, 4*x + 3);
return 0;
}
int f(int x, int y) {
return 2*x;
}
24
Avaliacao Preguicosa
int main () {
int x = 2;
f(2*2, 4*2 + 3);
return 0;
}
int f(int x, int y) {
return 2*x;
}
25
Avaliacao Preguicosa
int main () {
int x = 2;
f(4, 4*x + 3);
return 0;
}
int f(int x, int y) {
return 2*x;
}
26
Avaliacao Preguicosa
int main () {
int x = 2;
f(4, 11);
return 0;
}
int f(int x, int y) {
return 2*x;
}
27
Avaliacao Preguicosa
f x y = 2*x
main = do
let z = 2
print (8)
A expressao 4 ∗ z + 3 nunca foi avaliada!
31
Haskell: ghc e ghci
Glasgow Haskell Compiler: compilador de codigo aberto para a linguagem
Haskell.
Possui um modo interativo ghci (similar ao iPython).
33
Glasgow Haskell Compiler
Uso recomendado de:
Git - controle de revisao Cabal - gerenciamento de projeto e
dependencias Haddock - documentacao
$ mkdir hello
$ cd hello
$ mkdir bin
$ vim Hello.hs
34
Primeiro projeto
Hello.hs:
--
-- Copyright (c) 2017 Nome - site
-- GPL version 3 or later
-- (see http://www.gnu.org/copyleft/gpl.html)
--
-- | Modulo principal
module Main where
-- |Func~ao principal
main :: IO ()
main = do
print ("Hello World")
35
Primeiro projeto
Indica que esse e o modulo principal que ira gerar o executavel.
module Main where
36
Primeiro projeto
Funcao principal e uma funcao que nao recebe parametros e retorna uma
entrada e/ou saıda de arquivos.
main :: IO ()
37
Primeiro projeto
Para saber mais Criando um projeto usando Cabal (projetos grandes, nao
didaticos):
https://wiki.haskell.org/How to write a Haskell program
42
Para a disciplina
Criem um repositorio no github com o nome BIGDATA2018, coloquem
todos seus codigos la!
Os codigos dados em aula estarao em:
http://github.com/folivetti/BIGDATA.
43
Tipos de Dados
Haskell tem a tipagem forte e estatica.
Voce nao pode misturar tipos e esses devem ser bem definidos:
let x = 1 :: Integer
x + "texto" -- erro! N~ao pode somar um numero a um texto
x * 2.0 -- erro! O valor inteiro n~ao se transforma em real
x * 2 -- ok!
44
Tipos numericos
Int: inteiros de 32 ou 64 bits
Integer: Inteiros de precisao arbitraria
Float: ponto-flutuante precisao simples
Double: ponto-flutuante precisao dupla
45
Operadores
soma x y = x + y
subtrai x y = x - y
multiplica x y = x * y
divide x y = x / y
Prelude> :t (+)
(+) :: Num a => a -> a -> a
46
Operadores
soma x y = x + y
subtrai x y = x - y
multiplica x y = x * y
divide x y = x / y
Prelude> :t (/)
(/) :: Fractional a => a -> a -> a
47
Operadores
div/mod - arredonda na direcao de −∞
quot/rem - arredonda na direcao de 0
divideInt1 x y = x ‘div‘ y
divideInt1 x y = x ‘quot‘ y
resto1 x y = x ‘mod‘ y
resto2 x y = x ‘rem‘ y
48
Operadores
elevado1 x y = x ^ y
elevado2 x y = x ** y
(^) :: (Num a, Integral b) => a -> b -> a
(**) :: Floating a => a -> a -> a
49
Classes de tipos
Integral: todos os tipos inteiros
Floating: todos os tipos reais
Num: todos os numeros
50
Exercıcio
Qual o tipo dessa expressao?
aurea :: Floating a => a
aurea = (1 + sqrt 5) / 2
(poderia ser Double, ne?)
53
Bool
igual x y = x == y
diferente x y = x /= y
maior x y = x > y
menor x y = x < y
maiorIgual x y = x >= y
menorIgual x y = x <= y
55
Bool
True && True == True
True && False == False
True || False == True
False || False == False
not True == False
56
Ano bissexto
bissexto ano = (ano ‘rem‘ 400 == 0) || ((ano ‘rem‘ 4 == 0)
&& (ano ‘rem‘ 100 /= 0))
Na pratica podemos deixar o codigo mais enxuto...
57
Funcoes
O Haskell e baseado no Lambda Calculus em que a computacao e
baseada em funcoes de uma variavel.
Toda funcao recebe uma entrada e retorna uma saıda!
somaUm :: Integer -> Integer
somaUm x = x + 1
59
Funcoes de Uma Variavel
somaUm
Nome da funcao deve comecar com caixa baixa. O estilo padrao e o
camelCase.
60
Mais de uma variavel
Funcoes de mais de uma variavel, na verdade sao composicoes de funcoes:
soma x y = x + y
Na verdade e:
soma x y = (soma x) (y) -- resultado de soma x aplicado em y
soma x y = \z -> x + z (y)
67
Mais de uma variavel
soma :: Integer -> (Integer -> Integer)
soma e uma funcao que recebe um inteiro e retorna uma funcao que
recebe um inteiro e retorna um inteiro.
Para facilitar removemos os parenteses e fazemos a leitura como funcoes
de multiplas variaveis.
68
”Constantes
Quando fazemos:
pi = 3.14
Nao estamos declarando uma constante, mas sim uma funcao que nao
recebe parametros e retorna sempre o valor 3.14.
69
”Constantes
Quando fazemos:
pi :: Double
pi = 3.14
Nao estamos declarando uma constante, mas sim uma funcao que nao
recebe parametros e retorna sempre o valor 3.14.
70
Assinatura
soma :: Integer -> Integer -> Integer
Essa e a assinatura da funcao, ela costuma dizer muito sobre o que ela
faz.
71
Assinatura de classes
Quando queremos criar uma funcao que recebe classes de tipos (ex.:
Num) fazemos:
soma :: Num a => a -> a -> a
Se x e y forem inteiros, a funcao retornara um inteiro; se forem Double,
ela retornara Double; se forem diferentes entre si, retornara um erro!
72
Assinatura genericas
Podemos tambem criar funcoes que recebem qualquer tipo:
f :: a -> a -> b
Funcao que recebe duas variaveis de um mesmo tipo qualquer e retorna
uma variavel de outro tipo.
Aqui a, b sao apenas nomes genericos, pode ser qualquer outra letra.
73
Exercıcio
Crie uma funcao que receba 3 valores do tipo Double: a, b, c e retorne as
raızes da equacao:
a · x2 + b · x + c .
76
Exercıcio
raizSegGrau :: Double -> Double -> Double -> (Double, Double)
raizSegGrau a b c = ((-b - (sqrt (b**2 - 4*a*c)))/(2*a),
(-b + (sqrt (b**2 - 4*a*c)))/(2*a))
80
Beleza prometida
Podemos segmentar as definicoes de expressoes atraves da instrucao
where.
f x = expr
where
expr = expr1 + expr2
81
Beleza prometida
O Haskell (assim como o Python) usa espacos para definir blocos.
Lembre-se de manter seu codigo alinhado!
f x = expr
where
expr = expr1 + expr2
82
Beleza prometida
Muito melhor!
raizSegGrau :: Double -> Double -> Double -> (Double, Double)
raizSegGrau a b c = (x1, x2)
where
x1 = (-b - sqrt delta) / (2*a)
x2 = (-b + sqrt delta) / (2*a)
delta = b**2 - 4*a*c
83
Beleza prometida
Mas e se delta for negativo???
raizSegGrau :: Double -> Double -> Double -> (Double, Double)
raizSegGrau a b c = (x1, x2)
where
x1 = (-b - sqrt delta) / (2*a)
x2 = (-b + sqrt delta) / (2*a)
delta = b**2 - 4*a*c
84
Guard!!
Os guards (|) criam um desvio condicional para tratar certas
possibilidades da sua funcao:
f x
| cond1 = expr1
| cond2 = expr2
| otherwise = expr3
where
expr1 = ...
expr2 = ...
expr3 = ...
Leia: a funcao f recebe um parametro x e, se a condicao cond1 for
verdadeira, retorne expr1, se cond2 for verdadeira, retorne expr2, caso
contrario, retorne expr3.
Equivalente a um switch..case.
85
Guard!!
raizSegGrau :: Double -> Double -> Double -> (Double, Double)
raizSegGrau a b c
| delta < 0 = error "Raızes negativas!"
| otherwise = (x1, x2)
where
x1 = (-b - sqrt delta) / (2*a)
x2 = (-b + sqrt delta) / (2*a)
delta = b**2 - 4*a*c
86
Exercıcio
Reescreva a seguinte funcao utilizando os conceitos aprendidos ate entao:
bissexto ano = (ano ‘rem‘ 400 == 0) || ((ano ‘rem‘ 4 == 0)
&& (ano ‘rem‘ 100 /= 0))
87
Exercıcio
bissexto ano
| ano ‘divide‘ 400 = True
| ano ‘divide‘ 4 = not $ ano ‘divide‘ 100
where
divide x y = x ‘rem‘ y == 0
88
Pattern Matching
E possıvel tambem prever alguns casos triviais de entrada.
Considere a funcao:
mult :: Num a => a -> a -> a
mult x y = x * y
89
Pattern Matching
mult :: (Eq a, Num a) => a -> a -> a
mult 1 y = y
mult x 1 = x
mult 0 _ = 0
mult _ 0 = 0
mult x y = x * y
91
Pattern Matching
Classe Eq indica que sao numeros que permitem comparacao de
igualdade.
mult :: (Eq a, Num a) => a -> a -> a
mult 1 y = y
mult x 1 = x
mult 0 _ = 0
mult _ 0 = 0
mult x y = x * y
92
Pattern Matching
significa ”nao me importo com esse valor”
mult :: (Eq a, Num a) => a -> a -> a
mult 1 y = y
mult x 1 = x
mult 0 _ = 0
mult _ 0 = 0
mult x y = x * y
Os padroes sao avaliados de cima para baixo ate que um caso verdadeiro
seja encontrado.
93
Exercıcio
Use Pattern Matching para definir a funcao soma:
soma :: (Eq a, Num a) => a -> a-> a
soma x y = x + y
94
Exercıcio
Use Pattern Matching para definir a funcao soma:
soma :: (Eq a, Num a) => a -> a-> a
soma 0 y = y
soma x 0 = x
soma x y = x + y
95
Composicao de funcoes
Digamos que temos duas funcoes:
• Uma para calcular a nota numerica final
• Outra para transformar a nota em conceito
96
Composicao de funcoes
mediaFinal :: Double -> Double -> Double
mediaFinal p1 p2 = 0.4*p1 + 0.6*p2
conceito :: Double -> Char
conceito media
| media < 5 = ’F’
| media < 6 = ’D’
| media < 7 = ’C’
| media < 8 = ’B’
| otherwise = ’A’
97
Composicao de funcoes
Para compor as duas funcoes podemos definir:
a$b indica que queremos aplicar a no resultado de b.
geraConceito :: Double -> Double -> Char
geraConceito p1 p2 = conceito $ mediaFinal p1 p2
98
Composicao de funcoes
Funcoes de uma variavel podem ser compostas com o operador ”.”
nota :: Double -> Double
nota x = x*2
conceito :: Double -> Char
conceito x
| x > 5 = ’A’
| otherwise = ’F’
calcConceito = conceito . nota
99
Exercıcio
Dada a funcao aoCubo e a funcao sqrt, utilize composicao de funcoes
para calcular a expressao:
f (x) =√
(x + y)3
aoCubo :: Num a => a -> a
aoCubo x = x^3
100
Exercıcio
Dada a funcao aoCubo e a funcao sqrt, utilize composicao de funcoes
para calcular a expressao:
f (x , y) =√
(x + y)3
aoCubo :: Num a => a -> a
aoCubo x = x^3
f :: Floating a => a -> a -> a
f x y = sqrt . aoCubo $ x + y
101
Recursao
A recursividade permite expressar ideias declarativas.
Composta por um ou mais casos bases (para que ela termine) e a
chamada recursiva.
n! = n.(n − 1)!
102
Recursao
fatorial :: Integer -> Integer
fatorial 0 = 1
fatorial 1 = 1
fatorial n = n * fatorial (n-1)
105
Recursao
fatorial :: Integer -> Integer
fatorial 0 = 1
fatorial 1 = 1
fatorial n = n * fatorial (n-1)
Casos bases primeiro!!
106
Estouro de pilha
Em muitas linguagens, a chamada recursiva suspende a operacao,
armazena o estado atual em uma pilha e tenta computar a chamada
recursiva.
Isso pode levar ao estouro de pilha.
107
Estouro de pilha
No haskell ele nao armazena o estado atual na pilha, mas expande a
expressao a ser calculada.
Efetivamente ele faz: 5! = 5 * 4! = 5 * 4 * 3! ...
108
Estouro de pilha
fatorial :: Integer -> Integer
fatorial 0 = 1
fatorial 1 = 1
fatorial n = fatorial’ n 1
where
fatorial’ 1 r = r
fatorial’ n r = fatorial’ (n-1) (n*r)
110
Multiplicacao Etıope
A multiplicacao Etıope de dois numeros m, n e dado pela seguinte regra:
• Se m for par, o resultado e a aplicacao da multiplicacao em
m/2, n ∗ 2.
• Se m for ımpar, o resultado a aplicacao da multiplicacao em
m/2, n ∗ 2 somados a n.
• Se m for igual a 1, retorne n.
111
Multiplicacao Etıope
Implemente o algoritmo recursivo da Multiplicacao Etıope. Em seguida,
faca a versao caudal.
113
Multiplicacao Etıope
etiope :: Integer -> Integer -> Integer
etiope m n
| m==1 = n
| par m = etiope (m ‘div‘ 2) (n * 2)
| otherwise = n + (etiope (m ‘div‘ 2) (n * 2))
114
Multiplicacao Etıope
etiope :: Integer -> Integer -> Integer
etiope m n = etiope’ m n 0
where
etiope’ m n r
| m==1 = n + r
| par m = etiope (m ‘div‘ 2) (n * 2) r
| otherwise = etiope (m ‘div‘ 2) (n * 2) (r+n)
115
Listas
Definicao recursiva: ou e uma lista vazia ou um elemento do tipo
generico a concatenado com uma lista de a.
data [a] = [] | a : [a]
(:) - concatenacao de elemento com lista
116
Criando listas
lista = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
lista1 = [1..10] -- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
lista2 = [0,2..10] -- [0, 2, 4, 6, 8, 10]
lista3 = [0,2..] -- [0, 2, 4, 6, 8, 10,..]
117
Criando listas
-- [2..20]
lista = [ 2*x | x <- [1..10] ]
-- [0,2,4..]
lista = [ 2*x | x <- [0..] ]
lista = [ expr x | x <- lista’ ]
118
Criando listas
-- [ (1*1), (1*2), ..., (2*1), (2*2) ... ]
-- produto cartesiano
lista = [ x*y | x <- [1..10], y <- [1..10] ]
lista = [ expr x y | x <- lista1, y <- lista2 ]
119
Criando listas
-- [5, 10, 15..]
lista = [ x | x <- [1..100], x ‘mod‘ 5 == 0]
lista = [ expr x | x <- lista’, se expr’ x for verdadeiro ]
120
Criando listas
-- [1,2..]
lista = 1 : prox lista
where
prox (x:resto) = (x+1) : prox resto
(x : resto) e um pattern match que captura o primeiro elemento da lista
em x e o restante da lista em resto.
121
Criando listas
-- [1,2..]
lista = 1 : prox lista
lista = 1 : prox [1]
lista = 1 : prox (1:[])
lista = 1 : (1+1) : prox [(1+1)]
...
122
Criando listas
Fibonacci:
fib = 1 : 2 : prox fib
where
prox (x : t@(y:z)) = (x+y) : prox t
O padrao (x : t@(y : )) captura:
• x e o primeiro elemento da lista.
• t e o restante da lista (tail).
• @ faz um pattern matching em t.
• y e o segundo elemento da lista.
• z e a lista sem os dois primeiros elementos.
123
Exercıcio
No jogo FizzBuzz, todo multiplo de 3 e substituıdo por Fizz, todo
multiplo de 5 e substituıdo por Buzz e todo multiplo de 3 e 5 e
substituıdo por FizzBuss.
Crie uma lista com os elementos que nao serao substituıdos.
124
Concatenacao
lista1 = [2,3,4]
lista2 = [1,2,3]
x = 1
lista3 = lista1 ++ lista2 -- [2,3,4,1,2,3]
lista4 = x : lista1 -- [1,2,34]
(:) : a -> [a] -> [a]
(++) : [a] -> [a] -> [a]
126
Propriedades
length :: [a] -> Int
length [] = 0
length (x:xs) = 1 + (length xs)
null :: [a] -> Bool
null [] = True
null _ = False
127
Sublistas
lista = [1..10]
take :: Int -> [a] -> [a]
take 0 xs = []
take n [] = []
take n (x:xs) = x : (take (n-1) xs)
take 2 lista -- [1,2]
128
Strings como Lista
Uma String em Haskell pode ser representada como uma lista do tipo
Char:
type String = [Char]
palavra = "Ola Mundo"
primeiraLetra :: String -> Char
primeiraLetra (w:ws) = w
primeiraLetra palavra -- ’O’
129
Trabalhando com Listas
Suponha as listas:
listaNum = [5, 3, 1, 2, 4]
listaStr = ["cachorro", "gato", "arara"]
130
Trabalhando com Listas
Digamos que queremos triplicar os numeros da primeira lista e colocar
uma exclamacao no final de cada string. Poderıamos fazer:
listaNum = [5, 3, 1, 2, 4]
listaTriplo = [3*x | x <- listaNum]
addExc (x:[]) = x : [’!’]
addExc (x:xs) = x : addExc xs
listaStr = ["cachorro", "gato", "arara"]
listaStrE = [addExc s | s <- listaStr]
131
Trabalhando com Listas
O padrao:
[f x | x <- lista]
e recorrente em muitos algoritmos, podemos criar uma funcao generica
map que sabe aplicar uma funcao f em qualquer tipo x .
132
Trabalhando com Listas
A funcao map recebe uma funcao que transforma um tipo a no tipo b,
uma lista do tipo a e retorna uma lista do tipo b. Note que a e b podem
ser iguais.
map :: (a -> b) -> [a] -> [b]
map f xs = [f x | x <- xs]
triplica x = 3*x
listaTriplo = map triplica listaNum
listaStrE = map addExc listaStr
133
Trabalhando com Listas
Digamos agora que queremos remover todos os valores ımpares de
listaTriplo:
listaTriploPar = [x | x <- listaTriplo, even x]
E tambem todos menores ou iguais a 4:
listaTriploPar = [x | x <- listaTriplo, even x, x > 4]
Esse tambem e um padrao recorrente que podemos deixar mais claro
utilizando a funcao filter.
134
Trabalhando com Listas
A funcao filter, recebe uma funcao que avalia um tipo a em um
booleano, uma lista do tipo a e retorna uma lista do mesmo tipo, filtrada
pelo predicado.
filter :: (a -> Bool) -> [a] -> [a]
filter f xs = [x | x <- xs, f x]
maiorQuatro x = x > 4
listaFinal = filter maiorQuatro
$ filter even
$ map triplica listaNum
Com isso conseguimos representar as operacoes como um fluxo de dados,
os elementos de listaNum passa pela funcao triplica para depois passar
pelo crivo de even e, finalmente, por maiorQuatro.
135
Funcoes anonimas
Quando as funcoes a serem passadas como parametro sao pequenas,
podemos utilizar as funcoes anonimas:
map (\x -> 3*x) listaNum
filter \x -> x > 4) listaTriplo
A sintaxe \ representa o sımbolo λ, entao devemos ler como funcao λ que
recebe um parametro x e retorna (→) uma expressao em funcao de x .
Note que as funcoes anonimas podem ter apenas uma unica expressao
simples.
136
Pointfree notation
Adicionalmente, quando a funcao ja esta definida ou e um operador
podemos utilizar o estilo pointfree:
map (3*) listaNum
map (*3) listaNum
filter (>4) listaTriplo
137
Exercıcio
Dada a seguinte funcao:
collatz :: Integer -> Integer
collatz n
| even n = n ‘div‘ 2
| otherwise = 3*n + 1
Gere uma lista com os elementos ımpares da aplicacao dessa funcao nos
numeros naturais.
138
Exercıcio
Dada a seguinte funcao:
collatz :: Integer -> Integer
collatz n
| even n = n ‘div‘ 2
| otherwise = 3*n + 1
lista = filter odd $ map collatz [1..]
Gere uma lista com os elementos ımpares da aplicacao dessa funcao nos
numeros naturais.
139
Trabalhando com Listas
Agora queremos somar os valores de listaFinal, para isso podemos criar
uma funcao:
sum :: Num a => [a] -> a
140
Trabalhando com Listas
Agora queremos somar os valores de qtdeBrinquedos, para isso podemos
criar uma funcao:
sum :: Num a => [a] -> a
sum [] = 0
sum (x:xs) = x + (sum xs)
total = sum listaFinal
141
Trabalhando com Listas
A funcao sum pode ser generalizada para qualquer tipo de operacao.
Digamos que queremos calcular a produtoria de uma lista. Como
podemos alterar sum?
sum :: Num a => [a] -> a
sum [] = 0
sum (x:xs) = x + (sum xs)
prod :: Num a => [a] -> a
142
Trabalhando com Listas
A funcao sum pode ser generalizada para qualquer tipo de operacao.
Digamos que queremos calcular a produtoria de uma lista. Como
podemos alterar sum?
sum :: Num a => [a] -> a
sum [] = 0
sum (x:xs) = x + (sum xs)
prod :: Num a => [a] -> a
prod [] = 1
pro (x:xs) = x * (prod xs)
Basicamente alteramos o valor neutro de 0 parar 1 e o operador aplicado
no caso generico.
143
Folding
Esse tipo de operacao e conhecido como fold ou reduce dependendo da
linguagem funcional. Basicamente essa operacao parte de um elemento
neutro e aplica uma operacao de reducao sequencialmente entre o
acumulador atual e o proximo elemento da lista:
foldr :: (a -> b -> a) -> a -> [b] -> a
foldr f z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
Uma funcao que agrega o resultado de um tipo a com um tipo b, um
elemento neutro a e uma lista de b, resultando em a.
144
Folding
Alternativamente podemos definir uma versao caudal:
foldl :: (a -> b -> a) -> a -> [b] -> a
foldl f z [] = z
foldl f z (x:xs) = foldl f (f z x) xs
145
Folding
Nossas funcoes soma e produtoria podem ser definidas como:
sum = foldl (+) 0
produtoria = foldl (*) 1
146
Exercıcio
Dada a definicao do operador &&:
(&&) False _ = False
(&&) _ False = False
(&&) _ _ = True
Expanda as seguintes expressoes:
foldl (&&) False [False, False, False, False]
foldr (&&) False [False, False, False, False]
147
Exercıcio
foldl (&&) (False && False) [False, False, False]
foldl (&&) ((False && False) && False) [False, False]
foldl (&&) (((False && False) && False) && False) [False]
foldl (&&) (((False && False) && False) && False) && False
(((False && False) && False) && False) && False
False
148
Trabalhando com Listas
Finalmente, temos as funcoes sort e nub que ordena uma lista e gera
apenas os elementos unicos, respectivamente:
sort :: Ord a => [a] -> [a]
nub :: Eq a => [a] -> [a]
150
Tipos de Dados Algebricos
Tipo soma:
data Bool = True | False
• data: declara que e um novo tipo
• Bool: nome do tipo
• True — False: poder assumir ou True ou False
152
Tipos de Dados Algebricos
Tipo produto:
data Ponto = Ponto Double Double
• data: declara que e um novo tipo
• Ponto: nome do tipo
• Ponto: construtor (ou envelope)
• Double Double: tipos que ele encapsula
153
Tipos de Dados Algebricos
Para ser possıvel imprimir esse tipo:
data Ponto = Ponto Double Double
deriving (Show)
• deriving: derivado de outra classe
• Show: tipo imprimıvel
Isso faz com que o Haskell crie automaticamente uma instancia da
funcao show para esse tipo de dado.
154
Convertendo entre tipos e String
A funcao read le uma String e converte para um tipo especıfico, a funcao
show converte um tipo para uma String.
x = read "2" :: Integer
y = read "2.3" :: Double
z = read "True" :: Bool
sx = show x
sy = show y
sz = show z
155
Tipos de Classe - deriving
Alem do Show temos os seguintes tipos de classe que podem ser
derivadas:
• Read: que podem ser lidas a partir de uma String
• Eq: que possuem relacao de igualdade
• Ord: possuem relacao de ordem
• Enum: que sao enumeraveis
• Bounded: possuem um limite inferior e superior
Caso o compilador nao consiga criar as funcoes pertinentes
automaticamente, sera necessario implementa-las.
156
Tipos de Classe - deriving
Outras duas funcoes importantes para conversao:
• fromIntegral: converte de um inteiro para um tipo da classe Num,
pertinente para a expressao a ser calculada
• fromEnum: converte para a posicao de um tipo enumeravel.
157
Tipos de Dados Algebricos
data Ponto = Ponto Double Double
deriving (Show)
main = do
print (Ponto 12.2 1.1)
Ponto 12.2 1.1
158
Tipos de Dados Algebricos
data Ponto = Ponto Double Double
deriving (Show)
dist :: Ponto -> Ponto -> Double
dist (Ponto x1 y1) (Ponto x2 y2) = sqrt $ (x1-x2)^2 + (y1-y2)^2
159
Tipos de Dados Algebricos
type Centro = Ponto
type Raio = Double
data Circ = Circ Centro Raio
deriving (Show)
type e um apelido para um tipo!
161
Tipos de Dados Algebricos
data Dias = Seg | Ter | Qua | Qui | Sex | Sab | Dom
deriving (Show, Enum)
Enum e enumerativo:
succ Seg == Ter
pred Ter == Seg
162
Tipos de Dados Algebricos
data Dias = Seg | Ter | Qua | Qui | Sex | Sab | Dom
deriving (Show, Enum, Eq)
Eq e comparativo de igualdade:
Seg == Ter -- False
Seg == Seg -- True
163
Tipos de Dados Algebricos
data Dias = Seg | Ter | Qua | Qui | Sex | Sab | Dom
deriving (Show, Enum, Ord)
Ord e relacional:
Seg < Ter -- True
Ter > Seg -- False
164
Tipos de Dados Algebricos
data List a = Nil | Cons a (List a)
Uma lista de tipo a e definido ou como vazio (Nil) ou como a constante
do tipo a e uma lista do tipo a.
[1,2,3] = Cons 1 (Cons 2 (Cons 3 Nil))
165
Tipos de Dados Algebricos
safeDiv :: Double -> Double -> Maybe Double
safeDiv x y
| y==0 = Nothing
| otherwise = Just (x / y)
media l = case safeDiv (sum l) (fromIntegral $ length l) of
Nothing -> 1/0 -- infinity
Just m -> m
167
Atividade 01
Faca os exercıcios das paginas Exercıcios Basicos, Exercıcios sobre
Funcoes e Exercıcios sobre Listas da seguinte pagina:
Curso de Haskell
168