Paradigma Funcional
Caso de Estudo:
Haskell
Sobre mim
Sérgio Souza Costa
Professor - UFMA
Doutor em Computação Aplicada (INPE)
prof.sergio.costa@gmail.com
https://sites.google.com/site/profsergiocosta/home
https://twitter.com/profsergiocosta
http://gplus.to/sergiosouzacosta
http://www.slideshare.net/skosta/presentations?order=popular
John McCarthy
(Boston, 4 de setembro de 1927 — 23 de outubro de 2011)
Criador da linguagem Lisp, segunda linguagem de programação.
Life is too short for imperative
programming
John Hughes
“ “
Paradigma Funcional
Linguagens onde as variáveis não mudam de valor durante a
execução. São imutáveis.
PARADIGMAS DE PROGRAMAÇÃO
É difícil programar em linguagem
funcional ?
Abra a cabeça
POO Vs Funcional
Programação orientada a objetos é um estilo de Programação
que permite:
● Reuso de código (via classes)
● Eliminação de bugs (via encapsulamento, ocultação de
dados )
POO Vs Funcional
Programação funcional é um estilo de programação
que permite:
- Reuso de código (composição de função)
- Eliminação de bug (via imutabilidade (não existe mudança de
valores de variáveis))
Vantagens
● Códigos sucintos e concisos
○ Menor tempo de desenvolvimento
○ Manutenabilidade
● Códigos seguros
● Reusabilidade
● Facilidade de escrita, suporte a abstrações
● Confiabilidade, segurança
Exemplo - Quick sort (Haskell)
qs [] = []
qs (x:xs) = qs [y | y <- xs, y < x]
++ [x]
++ qs [y | y <- xs, y >= x]
Exemplo - Quick sort (C)
int particao(int vec[], int inicio, int
fim) {
int i, j;
i = inicio;
for (j = inicio + 1; j <= fim; ++j) {
if (vec[j] < vec[inicio]) {
++i;
troca(&vec[i], &vec[j]);
}
}
troca(&vec[inicio], &vec[i]);
return i;
}
Exemplo - Quick sort (C)
void quickSort(int vec[], int inicio,
int fim)
{
int p;
if (fim > inicio) {
p = particao(vec, inicio, fim);
quickSort(vec, inicio, p - 1);
quickSort(vec, p + 1, fim);
}
Desvantagens
O computador não é funcional
● Maior custo de processamento
● Maior consumo de memória
Conceitos chaves
● Expressões
● Funções
● Polimorfismo paramétrico
E em algumas linguagens:
● Abstração de dados
● Avaliação preguiçosa.
Conceitos chaves
● Expressão é um conceito chave, pois seu propósito é
computar novos valores a partir de valores antigos, que é a
essência da programação funcional.
● Função é um conceito chave, pois funções generalizam
expressões. Além disso, funções são valores de primeira
classe, dado que podem ser argumento e resultado de
outras funções, fazer parte de valores compostos ..
Conceitos chaves
Abstração de dados é o conceito chave nas linguagens funcionais modernas, tais
como ML e HASKELL. Permitem criar novos tipos de dados a partir dos já
existentes.
Polimorfismo paramétrico é um conceito chave, pois ele permite que uma função
opere sobre valores de uma família de tipos, ao invés de apenas um tipo. Na
prática, muitas funções são naturalmente polimórficas, e o polimorfismo
paramétrico incrementar o poder e a expressividade das linguagens funcionais
Avaliação preguiçosa é baseada na noção que uma expressão só será avaliada se
for usada.
Caso de Estudo: Haskell
Haskell: Uma abordagem prática:
Real World Haskell
●http://book.realworldhaskell.org/read/
Haskell
● Uma linguagem puramente funcional
● Funções puras
● Funções são valores de primeira ordem
● Linguagem com diversos recursos avançados:
● Casamento de padrões
● Compreensão de lista
● Avaliação preguiçosa
● Polimorfismo parametrico
http://www.haskell.org/haskellwiki/Haskell_in_industry
Haskell na Indústria
Elementos básicos
● Expressões e funções
● Tipos e valores
● Tuplas
● Listas
Expressões
●
Em Haskell, construímos expressões a partir de:
● literais
● operadores e parentese
● aplicação de funções
Expressões
● Literais:
-3.459
True
'a'
"hello"
[1,2,4,9]
● Aplicação de funções:
even 47
twice (-2)
Operadores
. Composição de funções
*, /, ^ multip, divisão, potência
+ , - adição, subtração
:, ++ composição de listas, concatenação
==,/=,<=,... igual, desigual, comparação
&& E
|| OU
Estratégia call-by-value --- Avalia primeiro o
argumento antes de aplicar a função
(Pascal, C, Java, etc).
Estratégia call-by-name (ou AVALIAÇÃO
PREGUIÇOSA) --- Aplica imediatamente a
função ao argumento, adiando para mais
tarde a avaliação desse argumento (Haskell
e Miranda)
Estatégias de avaliação
Tipos em Haskell
O que é um tipo?
Tipo é um conjunto de valores que possuem um comportamento uniforme
sobre dadas operações. (David Watt)
“A program variable can assume a range of values during the execution of
a program. An upper bound of such a range is called a type of the variable”
(Cardelli)
Tipos em Haskell
Tipo é uma restrição
Descreve os limites do resultado final de uma computação
“The fundamental purpose of a type system is to prevent the
occurrence of execution errors during the running of a
program” (Cardelli).
Tipos primitivos
●Bool Boleanos
●Char Caracteres
●Int Inteiros de 32-bits
●Integer Inteiros de tam ilimitado
●Float Ponto flutuante
●Double Dupla precisão
Toda expressão tem um tipo
Os tipos podem ser inferidos
Prelude> :t (4 > 5)
(4 > 5) :: Bool
Prelude> :t (5+4)
(5+4) :: (Num t) => t
Prelude> :t [1.2,5.0]
[1.2,5.0] :: (Fractional t) => [t]
Função
● Correspondência biunívoca de membros do conjunto domínio para membros
do conjunto imagem
● Ordem de avaliação de suas expressões é controlada por expressões
condicionais
○ Não pela seqüência ou pela repetição iterativa
● Não têm efeitos colaterais
○ Sempre definem o mesmo valor dado o mesmo conjunto de argumentos, diferentemente de
um procedimento em linguagens imperativas.
Função
● Nome lista de parâmetros = expressão de correspondência
○ cubo x = x * x * x
● Um elemento do conjunto imagem é obtido para cada par: Nome da
função + um elemento particular do conjunto domínio
○ cubo 2.0 = 8.0
● Definição de uma função separada da tarefa de nomeá-la
○ Notação lambda (Church, 1941)
○ λ(x) x * x * x
f1 :: Int → Int → Int
f1 x y = x*y
Função
● A definição de uma função deve obedecer a sintaxe seguinte:
nome_função :: tipo_arg1 -> ... -> tipo_argN -> tipo_saída
nome_função arg1 ... argN = <expressão_resultado>
● Sendo tipo1,...,tipoN os tipos dos parâmetros de entrada da função.
Matemática
f (x)
f (x,y)
f (g(x))
f (x, g(y))
f (x) g(y)
f(a,b) + c d
Haskell
f x
f x y
f (g x) ou f $ g x
f x (g y) ou f $ g y
f x * g y
f a b + c * d
Função
Funções como valores de primeira classe
Significa que as funções têm um estatuto tão importante como o dos inteiros, reais,
e outros tipos predefinidos. Concretamente, numa linguagem funcional as funções
podem ...
● Ser passadas como argumento para outras funções;
● Podem ser retornadas por outras funções;
● Podem ser usadas como elementos constituintes de estruturas de dados;
Prelude>map (x->2*x) [1,2,3]
[2,4,6]
Expressão de seleção (ou condicional)
menor x y =
se x <= y então o resultado da expressão é x
senão o resultado é y
Considere uma função que dado dois valores, retorna o menor:
A estratégia para resolução do problema é com uso de uma expressão de seleção
Expressão de seleção
if <condição> then <resultado 1>
else <resultado2>
menor :: Int -> Int -> Int
menor x y = if x <= y then x
else y
-- fatorial
fat :: Integer -> Integer
fat 0 = 1
fat n = fat (n-1) * n
Casamento de padrões
Podemos especificar o comportamento de uma função descrevendo sua resposta
a diferentes situações de entrada.
● Podemos ter múltiplas definições
● Alternativa aos “ifs”
Listas
● Uma lista é uma sequência de valores ordenados
● Listas são homogêneas:
●todos os elementos da lista tem o mesmo tipo
● Listas são dinâmicas:
●não há restrição no tamanho de listas (incluindo listas infinitas)
Listas
Uma lista é composta sempre de dois segmentos: cabeça
(head) e corpo (tail). A cabeça é sempre o primeiro emento e
corpo é uma lista com os demais elementos.
Prelude> ['a','b','c','d']
"abcd"
Prelude> 'a':['b','c','d']
"abcd"
Listas em Haskell
●
● Três tipos de notação:
● construtores:
1 : 1 : 2 : 3 : 5 : 8 : []
● “colchetes":
[1, 1, 2, 3, 5, 8]
● strings (apenas para listas de caracteres):
['h', 'e', 'l', 'l', 'o'] = "hello"
Listas
Pode se definir uma lista indicando os limites inferior e superior:
[<limite-inferior> .. <limite-superior>]
Listas
Podemos definir qualquer progressão aritmética em uma lista utilizando a
seguinte notação:
[<termo1>, <termo2> .. <limite-superior>
Prelude> [0,3..21]
[0,3,6,9,12,15,18,21]
Prelude> [0,2..20]
[0,2,4,6,8,10,12,14,16,18,20]
Listas por compreensão
A definição de listas por compreensão é feita por um construtor de listas
que utiliza conceitos e notações da teoria dos conjuntos. Assim, para um
conjunto A temos:
Sendo E(x) uma expressão em X, onde X pertence a lista, dados um
conjunto de proposições Pi(x)
A = [E(x) | x <- lista, P1(x), ..., Pn(x)]
Por exemplo:
[x | x <- l1, even x, x < 100 ], todos pares menos que 100 pertencentes a l1
Compreensão de listas
● Um construtor de processamento de listas em linguagem de programação, a
notação matemática é a seguinte:
● Outros exemplos
● Por exemplo, as 10 primeiras potências de 2:
[2 ^ x | x <- [1..10] ]
● Todos os números pares maiores que 1 e menores que 100:
[ x | x <- [1..100] , par x ]
Exemplo:
[x | x <- [1..1000], even x, x < 100 ]
[2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,
46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,8
4,86,88,90,92,94,96,98]
Compreensão de listas
Listas com mais um gerador
Compreensão de listas
isempty :: [a] -> Bool
isempty [] = True
isempty anythingElse = False
length [] = 0
length (x : xs) = 1 + length xs
head [] = error "head []"
head (x:xs) = x
Casamento de padrões (lista)
Recursão
length :: [a] -> Int
length [] = 0
length (x : xs) = 1 + length xs
Um conceito básico em Haskell é o uso de recursão para
definição de funções
Recursão
● Sem loops explícitos, o fluxo em Haskell é usualmente expresso por recursão.
● Como garantir que recursão termine?
○ Escolha uma “entidade” para focar o processo
○ Garanta que a próxima chamada estará mais próxima de uma condição de
término
Exemplos:
● Decrementar um valor para cada chamada
● Tomar um valor de uma lista a cada chamada
Recursão
●
A soma dos números de uma lista vazia
sumAll (x : xs) = x + sumAll xs
sumAll [] = 0
sumAll :: [Integer] -> Integer
Soma de todos os números de uma lista
Soma dos números de uma lista x : xs
Recursão
●
Concatenar uma lista vazia:
concat (s : ss) = s ++ concat ss
concat [] = [] --- = “”
concat :: [[Char]] -> [Char]
Concatenação de listas de caracteres
Concatenar uma lista a partir de um elemento:
Avaliação de Funções Recursivas
length [] = 0
length (x : xs) = 1 + (length xs)
length (1 : 2 : 4 : [])
1 + length (2 : 4 : [])
1 + 1 + length (4 : [])
1 + 1 + 1 + length []
1 + 1 + 1 + 0
Recursos avançados
●
1. Definições locais,
2. Importando bibliotecas externas,
3. Funções de segunda ordem
4. Trabalhando com entrada e saída
54
Definições locais
raizes (a, b, c) = (x1,x2)
where
delta = sqrt ( b^2 - 4*a*c)
x1 = ((-b) + delta) / (2*a)
x2 = ((-b) - delta) / (2*a)
55
Para uma melhor legibilidade de um código, podemos usar a
cláusula “where” para fazer definições visíveis somente por
uma dada função.
Sinônimos
type Point = (Int, Int)
type Polygon = [Point]
p1 :: Point
p1 = (1,4)
pol1:: Polygon
pol1 = [(1,1),(1,2),(3,1),(1,1)]
56
Em Haskell, é possível criar sinônimos de tipos, ex:
Avaliação parcial
57
Haskell distingue entre operadores and funções:
Operadores têm noção infixa (e.g. 1 + 2),
Funções usam notação prefixa (e.g. plus 1 2).
Operadores podem ser convertidos em funções colocando-os entre parênteses:
(+) m n = m + n.
Haskell aceita operadores com avaliação parcial. E.g.:
(+ m) n = m + n
(: 0) l = 0 : l
Avaliação parcial
multThree :: (Num a) => a -> a -> a -> a
multThree x y z = x * y * z
ghci> let multTwoWithNine = multThree 9
ghci> multTwoWithNine 2 3
54
ghci> let multWithEighteen =
multTwoWithNine 2
ghci> multWithEighteen 10
180
58
Avaliação parcial
divideByTen :: (Floating a) => a -> a
divideByTen = (/10)
59
A função divideByTen 200 é equivalente a 200 / 10, ou (/10)
200
Funções são valores de primeira classe
60
● Em linguagens funcionais, funções são valores de primeira classe.
● Não existe restrição sobre o uso de funções em linguagens funcionais,
● Podem ser argumentos de funções
● Saídas de funções
● Elementos de estrutura de dados
Funções como argumentos
twice :: (a -> a) -> a -> a
twice f x = f (f x)
61
Uma característica poderosa de Haskell é funções podem ser argumentos de
outras funções.
Estas funções são chamadas funções de segunda ordem.
Map
map :: (a -> b) -> [a] -> [b]
Main> map double [1,3,5,7]
[2,6,10,14]
62
A função map aplica uma função a todos os elementos de
uma lista.
Map pode ser definido por recursão ou por compreensão de
listas
Ou por compreensão de lista
Map
map :: (a -> b) -> [a] -> [b]
map f xs = [f x | x xs]
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x : xs) = (f x) : map f xs
63
ghci> map (+3) [1,5,3,1,6]
[4,8,6,4,9]
ghci> map (++ "!") ["BIFF", "BANG", "POW"]
["BIFF!","BANG!","POW!"]
ghci> map (replicate 3) [3..6]
[[3,3,3],[4,4,4],[5,5,5],[6,6,6]]
ghci> map (map (^2)) [[1,2],[3,4,5,6],[7,8]]
[[1,4],[9,16,25,36],[49,64]]
ghci> map fst [(1,2),(3,5),(6,3),(2,6),(2,5)]
[1,3,6,2,2]
64
Map
Map com avaliação parcial
Main> map (*5) [1,3,5,7]
[5,15,25,35]
incAll = map (1 +)
addNewlines = map (++ "n")
halveAll = map (/2)
squareAll = map (^2)
stringify = map (: [])
65
Filter
filter :: (a -> Bool) -> [a] -> [a]
Main> filter even [1..10]
[2,4,6,8,10]
66
A função filter seleciona os elementos de uma lista que
satisfazem a um predicado
Filter
filter :: (a -> Bool) -> [a] -> [a]
filter p xs = [x | x <- xs, p x]
filter p [] = []
filter p (x : xs)
| p x = x : filter p xs
| otherwise = filter p xs
67
Pode ser definido como compreensão de listas ou por recursão
Comprimindo para um único valor
f [] = v
f (x:xs) = x <- f xs
68
Um grande número de funções em listas podem ser definidas a partir de um
padrão simples de recursão
●A lista vazia recebe para um valor final, e uma lista
●não vazia é mapeada para um operador : que
●combina o primeiro elemento com a aplicação da função no resto da lista
Comprimindo para um único valor
sum [] = 0
sum (x:xs) = x + sum xs
product [] = 1
product (x:xs) = x * product xs
and [] = True
and (x:xs) = x && and xs
11/4/11 69
Comprimindo para um único valor
sum = foldr (+) 0
product = foldr (*) 1
and = foldr (&&) True
70
A função foldr (“fold right”) encapsula este padrão de recursão em listas, com a
função dada e o valor v como argumentos
Definição do foldr
foldr::(a -> b -> b) -> b -> [a] -> b
foldr f v [] = v
foldr f v (x:xs) =
f x (foldr f v xs)
71
Composição de Funções
(f . g) x = f (g x)
> ( (*2) . (*5) ) 8
> 80
72
Abstração de dados
73
Tipos enumerados (enumerated no C),
Tipos cartesianos (struct no C),
Uniões disjunta (union no C)
Tipos recursivos
O que vimos até então...
type Matricula = Int
type Nome = String
type Salario = Double
type Funcionario = (Matricula, Nome, Salario)
74
Usamos os tipos existentes em Haskell
● Primitivos: Int, String, Bool
● Compostos: Listas e tuplas
Aprendemos criar sinônimos :
Qual o problema com os sinônimos?
75
Qual o problema com os sinônimos?
76
type Matricula = Int
type Nome = String
type Salario = Double
type Funcionario = (Matricula, Nome, Salario)
funcionarios :: [Funcionario]
funcionarios = [(1235,"joao", 580), (256,"jose", 590)]
aumentaSalario :: Funcionario -> Funcionario
aumentaSalario (m,n,s) = (m,n,s+(0.1*s))
type Nota = Double
type Alunos = (Matricula, Nome, Nota)
alunos :: [Alunos]
alunos = [(1,"antonio", 50.6), (6,"maria", 70)]
– eu poderia aplicar aumentaSalario a um aluno, pois são a mesma tupla,
– apenas com nomes diferentes
Usando tipos algébricos do Haskell
Data Funcionario = Funcionario Int String Double
type Matricula = Int
type Nome = String
type Salario = Double
Data Funcionario = Funcionario Matricula Nome Salario
Nós definimos um novo tipo de dado usando o
palavra-chave data.
Tipos Compostos
78
Os tipos algébricos do Haskell permite estruturas diversos tipos a partir de valores
mais simples.
● Produto cartesiano ( registros)
● Tipos enumerados
● Uniões disjuntas (variantes e uniões)
● Tipos recursivos (estruturas de dados dinâmicas)
Tipos algébricos
data InfoLivro = Livro Int String [String]
Nome do tipo
Construtor de tipo
Diferenças entre nome de tipos e construtor de tipos:
O nome do tipo e dos construtores não precisa ser iguais.
Tipos algébricos
data Matricula = Matricula Int
deriving (Show, Ord, Eq)
Palavra chave
para derivar
classes
80
O Haskell dispõe diversas classes que podem ser derivadas para os novos
tipos.
●Show, permite vizualizar os dados na tela
●Ord, permite fazer comparaçoes, < e >
●Eq, permite verificar se dois tipos são iguais
Tipos algébricos – Registro
struct Point {
x,y: double;
};
data Point = Pt Double Double
deriving (Show)
C
Haskell
81
Tipos algébricos – Registro
data Point = Pt Double Double
deriving (Show)
getX :: Point → Double
getx Pt x y = x
getY :: Point → Double
getY Pt x y = x
82
Usando casamento de padrão para pegar um dado valor
Enumerandos
enum Dias {Segunda, Terça, Quarta,
Quinta, Sexta}
data Dias = Segunda | Terça | Quarta
| Quinta | Sexta deriving (Show)
C
Haskell
83
Tipo Booleano
data Booleano = Falso | Verdadeiro deriving (Show, Eq)
e :: Booleano -> Booleano -> Booleano
e Falso _ = Falso
e Verdadeiro b = b
maior :: Int -> Int -> Booleano
maior a b
| a > b = Verdadeiro
| otherwise = Falso
-- a é maior que b e c
maior3 a b c = (maior a b) `e` (maior a c)
-- maior3 7 5 6
84
União Disjunta em Haskell
data Number = Exact Int | Inexact Float
Valores:
Number = Exact Integer + Inexact Float
… Exact(–2) Exact(–1) Exact 0 Exact 1 Exact 2 …
… Inexact(–1.0) … Inexact 0.0 … Inexact 1.0 …
Cada valor consiste de uma tag, junto ou com
um valore inteiro (se a tag is Exact) ou um
valor Float (se a tag é Inexact).
85
Exemplo de união disjunta
data Number = Exact Int | Inexact Float deriving (Show)
pi2 = Inexact 3.1416
rounded :: Number -> Int
rounded (Exact i) = i
rounded (Inexact r) = round r
86
União Disjunta – Tratando erro
data Maybe a = Nothing | Just a
87
Em Haskell existe um tipo de dado muito util em casos onde uma função pode não
ter retorno.
●ex. buscar um elemento em uma lista
type Aluno = (Int, String)
busca :: Int -> [Aluno] -> Maybe String
busca mat [] = Nothing
busca mat ((x,y):xys)
| mat == x = Just y
| otherwise = busca mat xys
União Disjunta
union {
int exact;
int inexact;
};
data Number = Exact Int |
Inexact Float
HaskellC
88
Tipos Recursivos
data Nat = Zero | Succ Nat
data Lista = Nil | Cons Int Lista
data ArvoreBin = Vazia |
Nodo Int ArvoreBin ArvoreBin
89
Tipos Recursivos
Números naturais
data Nat = Zero | Succ Nat
Nat é um novo tipo com dois construtores
Zero :: Nat e Succ :: Nat -> Nat
90
Tipos recursivos
data Nat = Zero | Succ Nat deriving (Show)
soma :: Nat -> Nat -> Nat
soma Zero n = n
soma (Succ m) n = Succ (soma m n)
mult :: Nat -> Nat -> Nat
mult Zero m = Zero
mult (Succ m) n = soma n (mult n m)
91
Tipos Recursivos - Lista
data List =
Nil |
Cons Int List
deriving (Show)
first (Cons a s) = a
first Nil = error "vazio"
rest (Cons a s) = s
rest Nil = error "vazio"
92
Polimorfismo Paramétrico
C++
template <typedef T>
T maior (T a, T b) {
return ( (a>b)? a : b );
}
public class Pair<T, S>{
public Pair(T f, S s){
first = f;
second = s;
}
}
93
Java
Polimorfismo paramétrico
94
● Funções paramétricas
● Tipos de dados paramétrico
● Uma característica importante de Haskell é o uso de tipos paramétricos
● Muitas funções podem ser definidas em termos de tipos genéricos
● Convenção: usamos a, b, c para tipos genéricos
● Tipos paramétricos comuns, listas e tuplas
length :: [a] → Int
Tipos Paramétricos em Haskell
Pode ser lista de inteiros, de listas ..
95
data List a =
Nil |
Cons a List
deriving (Show)
first :: List a → a
first (Cons a s) = a
first Nil = error "vazio"
rest :: List a → List a
rest (Cons a s) = s
rest Nil = error "vazio"
data List Int =
Nil |
Cons Int List
deriving (Show)
first :: List → Int
first (Cons a s) = a
first Nil = error "vazio"
rest :: List → List
rest (Cons a s) = s
rest Nil = error "vazio"
Lista de inteiros Lista paramétrica
96
Tipos Paramétricos em Haskell
data ArvBin a = Vazia | Nodo a (ArvBin a) (ArvBin a)
deriving Show
elem :: ArvBin a -> a
elem Vazia = error "arvore vazia"
elem (Nodo e _ _) = e
esq :: ArvBin a -> ArvBin a
esq Vazia = error "arvore vazia"
esq (Nodo _ e _) = e
dir :: ArvBin a -> ArvBin a
dir Vazia = error "arvore vazia"
dir (Nodo _ _ d) = d
97
Tipos Paramétricos em Haskell
Definindo as funções de acesso
diretamente na definição
data ArvBin a = Vazia |
Nodo {
elem :: a,
esq :: (ArvBin a),
dir :: (ArvBin a)
} deriving Show
98
Restrição no polimorfismo
somatodos :: [a] -> a
somatodos (x:xs) = x + somatodos xs
99
Esta função pode ser aplicada a qualquer tipo ?
Restrição no polimorfismo
somatodos :: (Num a) => [a] -> a
somatodos (x:xs) = x + somatodos xs
100
Usando “type classes
A função somatodos funciona sobre qualquer “a”, desde que ele seja um Num.
Type class em Haskell
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
101
●Uma classe é uma coleção de tipos que suportam certas operações (métodos)
comuns
●Uma classe define uma assinatura, similar a uma interface
Classes Básicas em Haskell
Eq - tipos com igualdade
Ord – tipos ordenados
Show – tipos que podem ser transformados em strings
Read – tipos legíveis, que pode ser convertido
Num – tipos numéricos
102
Instanciando type class
data Point = Point Int Int deriving (Show, Eq, Ord,
Read)
instance Num Point where
(+) (Point x1 y1) (Point x2 y2)
= Point (x1 + x2) (y1 + y2)
103
data Point = Point Int Int
instance Show Point where
show (Point x y) = show (x,y)
Prelude> Point 4 5
> (4,5)
104
Instanciando type class
● Podemos instanciar qualquer uma das classes pré definidas, mesmo as
que são deriváveis, como Read, Show ...
Programas e
operações de
entrada e
saída
105
Operações de entrada e saída
106
Até então, vimos como usar o Haskell via ghci, mas como
gerar um programa compilável?
Como o Haskell consegue lidar com operações de entrada e
saída ?
Esse tipo de operação tem efeitos colaterais.
O problema ...
Um programa em
Haskell consiste
num conjunto de
funções, sem
efeitos colaterais
O objetivo de
executar qqer
programa é ter
algum efeito
colateral
Tensão
107
A solução
IO a
O tipo das ações de IO que retornam
um valor do tipo a
108
Escrever programas interativos em Haskell usando tipos que fazem
distinção entre expressões funcionais “puras” de ações “impuras” que
podem envolver efeitos colaterais
I/O em Haskell
IO Char
IO ()
O tipo das ações de IO que retornam
um caracter
O tipo das ações que não tem valor
de retorno
109
IO em Haskell: O tipo (IO a)
Um valor do tipo (IO t) é uma ação que, quando realizada, pode
fazer alguma forma de IO antes de devolver um resultado do
tipo t.
type IO a = World -> (a, World)
IO a
World outWorld in
result::a
110
Meu Primeiro Programa
Ou, compile em código nátivo.
module Main where
main = putStrLn "Hello World!"
runghc hello.hs
Hello World!
ghc hello.hs -o prg1
./prg1
Hello World!
111
Para rodar interpretado use o runghc:
Funções da biblioteca
112
Funções para escrever na tela
putStr :: String -> IO ()
putStrLn :: String -> IO ()
Para ler uma linha de caracteres do teclado, podemos usar a função:
getLine :: IO(String)
Combinando ações
Cada ação é nessa forma:
113
Para combinar ações podemos usar a notação “do”;
Meu segundo programa
module Main where
main = do
input <- getLine
putStrLn input
114
Lê uma entrada do usuário e imprime na tela
Meu terceiro programa
module Main where
ask :: String -> IO String
ask question = do
putStrLn question
getLine
main :: IO ()
main = do
nome <- ask "Qual eh o seu nome? "
matr <- ask "Qual eh a sua matricula?"
putStrLn ("Benvindo "++ nome ++ "!")
putStrLn ("Sua matricula eh "++matr)
115
Trabalhando com arquivos
import IO
import Data.Char
main = do
str <- readFile "input.txt"
writeFile "output.txt" (map toUpper str)
116
Converte todo um arquivo texto para letras maiúsculas.
A função readfile retorna uma string contendo todo o arquivo e writeFile escreve
uma string em um arquivo.
Funções para string
117
Função lines, quebra uma string pelo marcador de fim de linha
lines “linha1nlinha2”
= [“linha1”,linha 2]
Função words, quebra uma string por separador de palavras,”espaço”.
words “uma frase”
= [“uma”, frase]
Trabalhando com arquivos
main = do
str <- readFile "input.txt"
print (length (words str))
print (length (lines str))
118
FIM

Paradigma Funcional - Caso de Estudo Haskell

  • 1.
  • 2.
    Sobre mim Sérgio SouzaCosta Professor - UFMA Doutor em Computação Aplicada (INPE) prof.sergio.costa@gmail.com https://sites.google.com/site/profsergiocosta/home https://twitter.com/profsergiocosta http://gplus.to/sergiosouzacosta http://www.slideshare.net/skosta/presentations?order=popular
  • 3.
    John McCarthy (Boston, 4de setembro de 1927 — 23 de outubro de 2011) Criador da linguagem Lisp, segunda linguagem de programação.
  • 4.
    Life is tooshort for imperative programming John Hughes “ “
  • 5.
    Paradigma Funcional Linguagens ondeas variáveis não mudam de valor durante a execução. São imutáveis.
  • 6.
  • 7.
    É difícil programarem linguagem funcional ?
  • 8.
  • 9.
    POO Vs Funcional Programaçãoorientada a objetos é um estilo de Programação que permite: ● Reuso de código (via classes) ● Eliminação de bugs (via encapsulamento, ocultação de dados )
  • 10.
    POO Vs Funcional Programaçãofuncional é um estilo de programação que permite: - Reuso de código (composição de função) - Eliminação de bug (via imutabilidade (não existe mudança de valores de variáveis))
  • 11.
    Vantagens ● Códigos sucintose concisos ○ Menor tempo de desenvolvimento ○ Manutenabilidade ● Códigos seguros ● Reusabilidade ● Facilidade de escrita, suporte a abstrações ● Confiabilidade, segurança
  • 12.
    Exemplo - Quicksort (Haskell) qs [] = [] qs (x:xs) = qs [y | y <- xs, y < x] ++ [x] ++ qs [y | y <- xs, y >= x]
  • 13.
    Exemplo - Quicksort (C) int particao(int vec[], int inicio, int fim) { int i, j; i = inicio; for (j = inicio + 1; j <= fim; ++j) { if (vec[j] < vec[inicio]) { ++i; troca(&vec[i], &vec[j]); } } troca(&vec[inicio], &vec[i]); return i; }
  • 14.
    Exemplo - Quicksort (C) void quickSort(int vec[], int inicio, int fim) { int p; if (fim > inicio) { p = particao(vec, inicio, fim); quickSort(vec, inicio, p - 1); quickSort(vec, p + 1, fim); }
  • 15.
    Desvantagens O computador nãoé funcional ● Maior custo de processamento ● Maior consumo de memória
  • 16.
    Conceitos chaves ● Expressões ●Funções ● Polimorfismo paramétrico E em algumas linguagens: ● Abstração de dados ● Avaliação preguiçosa.
  • 17.
    Conceitos chaves ● Expressãoé um conceito chave, pois seu propósito é computar novos valores a partir de valores antigos, que é a essência da programação funcional. ● Função é um conceito chave, pois funções generalizam expressões. Além disso, funções são valores de primeira classe, dado que podem ser argumento e resultado de outras funções, fazer parte de valores compostos ..
  • 18.
    Conceitos chaves Abstração dedados é o conceito chave nas linguagens funcionais modernas, tais como ML e HASKELL. Permitem criar novos tipos de dados a partir dos já existentes. Polimorfismo paramétrico é um conceito chave, pois ele permite que uma função opere sobre valores de uma família de tipos, ao invés de apenas um tipo. Na prática, muitas funções são naturalmente polimórficas, e o polimorfismo paramétrico incrementar o poder e a expressividade das linguagens funcionais Avaliação preguiçosa é baseada na noção que uma expressão só será avaliada se for usada.
  • 19.
    Caso de Estudo:Haskell Haskell: Uma abordagem prática: Real World Haskell ●http://book.realworldhaskell.org/read/
  • 20.
    Haskell ● Uma linguagempuramente funcional ● Funções puras ● Funções são valores de primeira ordem ● Linguagem com diversos recursos avançados: ● Casamento de padrões ● Compreensão de lista ● Avaliação preguiçosa ● Polimorfismo parametrico
  • 21.
  • 22.
    Elementos básicos ● Expressõese funções ● Tipos e valores ● Tuplas ● Listas
  • 23.
    Expressões ● Em Haskell, construímosexpressões a partir de: ● literais ● operadores e parentese ● aplicação de funções
  • 24.
  • 25.
    Operadores . Composição defunções *, /, ^ multip, divisão, potência + , - adição, subtração :, ++ composição de listas, concatenação ==,/=,<=,... igual, desigual, comparação && E || OU
  • 26.
    Estratégia call-by-value ---Avalia primeiro o argumento antes de aplicar a função (Pascal, C, Java, etc). Estratégia call-by-name (ou AVALIAÇÃO PREGUIÇOSA) --- Aplica imediatamente a função ao argumento, adiando para mais tarde a avaliação desse argumento (Haskell e Miranda) Estatégias de avaliação
  • 27.
    Tipos em Haskell Oque é um tipo? Tipo é um conjunto de valores que possuem um comportamento uniforme sobre dadas operações. (David Watt) “A program variable can assume a range of values during the execution of a program. An upper bound of such a range is called a type of the variable” (Cardelli)
  • 28.
    Tipos em Haskell Tipoé uma restrição Descreve os limites do resultado final de uma computação “The fundamental purpose of a type system is to prevent the occurrence of execution errors during the running of a program” (Cardelli).
  • 29.
    Tipos primitivos ●Bool Boleanos ●CharCaracteres ●Int Inteiros de 32-bits ●Integer Inteiros de tam ilimitado ●Float Ponto flutuante ●Double Dupla precisão
  • 30.
    Toda expressão temum tipo Os tipos podem ser inferidos Prelude> :t (4 > 5) (4 > 5) :: Bool Prelude> :t (5+4) (5+4) :: (Num t) => t Prelude> :t [1.2,5.0] [1.2,5.0] :: (Fractional t) => [t]
  • 31.
    Função ● Correspondência biunívocade membros do conjunto domínio para membros do conjunto imagem ● Ordem de avaliação de suas expressões é controlada por expressões condicionais ○ Não pela seqüência ou pela repetição iterativa ● Não têm efeitos colaterais ○ Sempre definem o mesmo valor dado o mesmo conjunto de argumentos, diferentemente de um procedimento em linguagens imperativas.
  • 32.
    Função ● Nome listade parâmetros = expressão de correspondência ○ cubo x = x * x * x ● Um elemento do conjunto imagem é obtido para cada par: Nome da função + um elemento particular do conjunto domínio ○ cubo 2.0 = 8.0 ● Definição de uma função separada da tarefa de nomeá-la ○ Notação lambda (Church, 1941) ○ λ(x) x * x * x
  • 33.
    f1 :: Int→ Int → Int f1 x y = x*y Função ● A definição de uma função deve obedecer a sintaxe seguinte: nome_função :: tipo_arg1 -> ... -> tipo_argN -> tipo_saída nome_função arg1 ... argN = <expressão_resultado> ● Sendo tipo1,...,tipoN os tipos dos parâmetros de entrada da função.
  • 34.
    Matemática f (x) f (x,y) f(g(x)) f (x, g(y)) f (x) g(y) f(a,b) + c d Haskell f x f x y f (g x) ou f $ g x f x (g y) ou f $ g y f x * g y f a b + c * d Função
  • 35.
    Funções como valoresde primeira classe Significa que as funções têm um estatuto tão importante como o dos inteiros, reais, e outros tipos predefinidos. Concretamente, numa linguagem funcional as funções podem ... ● Ser passadas como argumento para outras funções; ● Podem ser retornadas por outras funções; ● Podem ser usadas como elementos constituintes de estruturas de dados; Prelude>map (x->2*x) [1,2,3] [2,4,6]
  • 36.
    Expressão de seleção(ou condicional) menor x y = se x <= y então o resultado da expressão é x senão o resultado é y Considere uma função que dado dois valores, retorna o menor: A estratégia para resolução do problema é com uso de uma expressão de seleção
  • 37.
    Expressão de seleção if<condição> then <resultado 1> else <resultado2> menor :: Int -> Int -> Int menor x y = if x <= y then x else y
  • 38.
    -- fatorial fat ::Integer -> Integer fat 0 = 1 fat n = fat (n-1) * n Casamento de padrões Podemos especificar o comportamento de uma função descrevendo sua resposta a diferentes situações de entrada. ● Podemos ter múltiplas definições ● Alternativa aos “ifs”
  • 39.
    Listas ● Uma listaé uma sequência de valores ordenados ● Listas são homogêneas: ●todos os elementos da lista tem o mesmo tipo ● Listas são dinâmicas: ●não há restrição no tamanho de listas (incluindo listas infinitas)
  • 40.
    Listas Uma lista écomposta sempre de dois segmentos: cabeça (head) e corpo (tail). A cabeça é sempre o primeiro emento e corpo é uma lista com os demais elementos. Prelude> ['a','b','c','d'] "abcd" Prelude> 'a':['b','c','d'] "abcd"
  • 41.
    Listas em Haskell ● ●Três tipos de notação: ● construtores: 1 : 1 : 2 : 3 : 5 : 8 : [] ● “colchetes": [1, 1, 2, 3, 5, 8] ● strings (apenas para listas de caracteres): ['h', 'e', 'l', 'l', 'o'] = "hello"
  • 42.
    Listas Pode se definiruma lista indicando os limites inferior e superior: [<limite-inferior> .. <limite-superior>]
  • 43.
    Listas Podemos definir qualquerprogressão aritmética em uma lista utilizando a seguinte notação: [<termo1>, <termo2> .. <limite-superior> Prelude> [0,3..21] [0,3,6,9,12,15,18,21] Prelude> [0,2..20] [0,2,4,6,8,10,12,14,16,18,20]
  • 44.
    Listas por compreensão Adefinição de listas por compreensão é feita por um construtor de listas que utiliza conceitos e notações da teoria dos conjuntos. Assim, para um conjunto A temos: Sendo E(x) uma expressão em X, onde X pertence a lista, dados um conjunto de proposições Pi(x) A = [E(x) | x <- lista, P1(x), ..., Pn(x)] Por exemplo: [x | x <- l1, even x, x < 100 ], todos pares menos que 100 pertencentes a l1
  • 45.
    Compreensão de listas ●Um construtor de processamento de listas em linguagem de programação, a notação matemática é a seguinte: ● Outros exemplos ● Por exemplo, as 10 primeiras potências de 2: [2 ^ x | x <- [1..10] ] ● Todos os números pares maiores que 1 e menores que 100: [ x | x <- [1..100] , par x ]
  • 46.
    Exemplo: [x | x<- [1..1000], even x, x < 100 ] [2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44, 46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,8 4,86,88,90,92,94,96,98] Compreensão de listas
  • 47.
    Listas com maisum gerador Compreensão de listas
  • 48.
    isempty :: [a]-> Bool isempty [] = True isempty anythingElse = False length [] = 0 length (x : xs) = 1 + length xs head [] = error "head []" head (x:xs) = x Casamento de padrões (lista)
  • 49.
    Recursão length :: [a]-> Int length [] = 0 length (x : xs) = 1 + length xs Um conceito básico em Haskell é o uso de recursão para definição de funções
  • 50.
    Recursão ● Sem loopsexplícitos, o fluxo em Haskell é usualmente expresso por recursão. ● Como garantir que recursão termine? ○ Escolha uma “entidade” para focar o processo ○ Garanta que a próxima chamada estará mais próxima de uma condição de término Exemplos: ● Decrementar um valor para cada chamada ● Tomar um valor de uma lista a cada chamada
  • 51.
    Recursão ● A soma dosnúmeros de uma lista vazia sumAll (x : xs) = x + sumAll xs sumAll [] = 0 sumAll :: [Integer] -> Integer Soma de todos os números de uma lista Soma dos números de uma lista x : xs
  • 52.
    Recursão ● Concatenar uma listavazia: concat (s : ss) = s ++ concat ss concat [] = [] --- = “” concat :: [[Char]] -> [Char] Concatenação de listas de caracteres Concatenar uma lista a partir de um elemento:
  • 53.
    Avaliação de FunçõesRecursivas length [] = 0 length (x : xs) = 1 + (length xs) length (1 : 2 : 4 : []) 1 + length (2 : 4 : []) 1 + 1 + length (4 : []) 1 + 1 + 1 + length [] 1 + 1 + 1 + 0
  • 54.
    Recursos avançados ● 1. Definiçõeslocais, 2. Importando bibliotecas externas, 3. Funções de segunda ordem 4. Trabalhando com entrada e saída 54
  • 55.
    Definições locais raizes (a,b, c) = (x1,x2) where delta = sqrt ( b^2 - 4*a*c) x1 = ((-b) + delta) / (2*a) x2 = ((-b) - delta) / (2*a) 55 Para uma melhor legibilidade de um código, podemos usar a cláusula “where” para fazer definições visíveis somente por uma dada função.
  • 56.
    Sinônimos type Point =(Int, Int) type Polygon = [Point] p1 :: Point p1 = (1,4) pol1:: Polygon pol1 = [(1,1),(1,2),(3,1),(1,1)] 56 Em Haskell, é possível criar sinônimos de tipos, ex:
  • 57.
    Avaliação parcial 57 Haskell distingueentre operadores and funções: Operadores têm noção infixa (e.g. 1 + 2), Funções usam notação prefixa (e.g. plus 1 2). Operadores podem ser convertidos em funções colocando-os entre parênteses: (+) m n = m + n. Haskell aceita operadores com avaliação parcial. E.g.: (+ m) n = m + n (: 0) l = 0 : l
  • 58.
    Avaliação parcial multThree ::(Num a) => a -> a -> a -> a multThree x y z = x * y * z ghci> let multTwoWithNine = multThree 9 ghci> multTwoWithNine 2 3 54 ghci> let multWithEighteen = multTwoWithNine 2 ghci> multWithEighteen 10 180 58
  • 59.
    Avaliação parcial divideByTen ::(Floating a) => a -> a divideByTen = (/10) 59 A função divideByTen 200 é equivalente a 200 / 10, ou (/10) 200
  • 60.
    Funções são valoresde primeira classe 60 ● Em linguagens funcionais, funções são valores de primeira classe. ● Não existe restrição sobre o uso de funções em linguagens funcionais, ● Podem ser argumentos de funções ● Saídas de funções ● Elementos de estrutura de dados
  • 61.
    Funções como argumentos twice:: (a -> a) -> a -> a twice f x = f (f x) 61 Uma característica poderosa de Haskell é funções podem ser argumentos de outras funções. Estas funções são chamadas funções de segunda ordem.
  • 62.
    Map map :: (a-> b) -> [a] -> [b] Main> map double [1,3,5,7] [2,6,10,14] 62 A função map aplica uma função a todos os elementos de uma lista.
  • 63.
    Map pode serdefinido por recursão ou por compreensão de listas Ou por compreensão de lista Map map :: (a -> b) -> [a] -> [b] map f xs = [f x | x xs] map :: (a -> b) -> [a] -> [b] map f [] = [] map f (x : xs) = (f x) : map f xs 63
  • 64.
    ghci> map (+3)[1,5,3,1,6] [4,8,6,4,9] ghci> map (++ "!") ["BIFF", "BANG", "POW"] ["BIFF!","BANG!","POW!"] ghci> map (replicate 3) [3..6] [[3,3,3],[4,4,4],[5,5,5],[6,6,6]] ghci> map (map (^2)) [[1,2],[3,4,5,6],[7,8]] [[1,4],[9,16,25,36],[49,64]] ghci> map fst [(1,2),(3,5),(6,3),(2,6),(2,5)] [1,3,6,2,2] 64 Map
  • 65.
    Map com avaliaçãoparcial Main> map (*5) [1,3,5,7] [5,15,25,35] incAll = map (1 +) addNewlines = map (++ "n") halveAll = map (/2) squareAll = map (^2) stringify = map (: []) 65
  • 66.
    Filter filter :: (a-> Bool) -> [a] -> [a] Main> filter even [1..10] [2,4,6,8,10] 66 A função filter seleciona os elementos de uma lista que satisfazem a um predicado
  • 67.
    Filter filter :: (a-> Bool) -> [a] -> [a] filter p xs = [x | x <- xs, p x] filter p [] = [] filter p (x : xs) | p x = x : filter p xs | otherwise = filter p xs 67 Pode ser definido como compreensão de listas ou por recursão
  • 68.
    Comprimindo para umúnico valor f [] = v f (x:xs) = x <- f xs 68 Um grande número de funções em listas podem ser definidas a partir de um padrão simples de recursão ●A lista vazia recebe para um valor final, e uma lista ●não vazia é mapeada para um operador : que ●combina o primeiro elemento com a aplicação da função no resto da lista
  • 69.
    Comprimindo para umúnico valor sum [] = 0 sum (x:xs) = x + sum xs product [] = 1 product (x:xs) = x * product xs and [] = True and (x:xs) = x && and xs 11/4/11 69
  • 70.
    Comprimindo para umúnico valor sum = foldr (+) 0 product = foldr (*) 1 and = foldr (&&) True 70 A função foldr (“fold right”) encapsula este padrão de recursão em listas, com a função dada e o valor v como argumentos
  • 71.
    Definição do foldr foldr::(a-> b -> b) -> b -> [a] -> b foldr f v [] = v foldr f v (x:xs) = f x (foldr f v xs) 71
  • 72.
    Composição de Funções (f. g) x = f (g x) > ( (*2) . (*5) ) 8 > 80 72
  • 73.
    Abstração de dados 73 Tiposenumerados (enumerated no C), Tipos cartesianos (struct no C), Uniões disjunta (union no C) Tipos recursivos
  • 74.
    O que vimosaté então... type Matricula = Int type Nome = String type Salario = Double type Funcionario = (Matricula, Nome, Salario) 74 Usamos os tipos existentes em Haskell ● Primitivos: Int, String, Bool ● Compostos: Listas e tuplas Aprendemos criar sinônimos :
  • 75.
    Qual o problemacom os sinônimos? 75
  • 76.
    Qual o problemacom os sinônimos? 76 type Matricula = Int type Nome = String type Salario = Double type Funcionario = (Matricula, Nome, Salario) funcionarios :: [Funcionario] funcionarios = [(1235,"joao", 580), (256,"jose", 590)] aumentaSalario :: Funcionario -> Funcionario aumentaSalario (m,n,s) = (m,n,s+(0.1*s)) type Nota = Double type Alunos = (Matricula, Nome, Nota) alunos :: [Alunos] alunos = [(1,"antonio", 50.6), (6,"maria", 70)] – eu poderia aplicar aumentaSalario a um aluno, pois são a mesma tupla, – apenas com nomes diferentes
  • 77.
    Usando tipos algébricosdo Haskell Data Funcionario = Funcionario Int String Double type Matricula = Int type Nome = String type Salario = Double Data Funcionario = Funcionario Matricula Nome Salario Nós definimos um novo tipo de dado usando o palavra-chave data.
  • 78.
    Tipos Compostos 78 Os tiposalgébricos do Haskell permite estruturas diversos tipos a partir de valores mais simples. ● Produto cartesiano ( registros) ● Tipos enumerados ● Uniões disjuntas (variantes e uniões) ● Tipos recursivos (estruturas de dados dinâmicas)
  • 79.
    Tipos algébricos data InfoLivro= Livro Int String [String] Nome do tipo Construtor de tipo Diferenças entre nome de tipos e construtor de tipos: O nome do tipo e dos construtores não precisa ser iguais.
  • 80.
    Tipos algébricos data Matricula= Matricula Int deriving (Show, Ord, Eq) Palavra chave para derivar classes 80 O Haskell dispõe diversas classes que podem ser derivadas para os novos tipos. ●Show, permite vizualizar os dados na tela ●Ord, permite fazer comparaçoes, < e > ●Eq, permite verificar se dois tipos são iguais
  • 81.
    Tipos algébricos –Registro struct Point { x,y: double; }; data Point = Pt Double Double deriving (Show) C Haskell 81
  • 82.
    Tipos algébricos –Registro data Point = Pt Double Double deriving (Show) getX :: Point → Double getx Pt x y = x getY :: Point → Double getY Pt x y = x 82 Usando casamento de padrão para pegar um dado valor
  • 83.
    Enumerandos enum Dias {Segunda,Terça, Quarta, Quinta, Sexta} data Dias = Segunda | Terça | Quarta | Quinta | Sexta deriving (Show) C Haskell 83
  • 84.
    Tipo Booleano data Booleano= Falso | Verdadeiro deriving (Show, Eq) e :: Booleano -> Booleano -> Booleano e Falso _ = Falso e Verdadeiro b = b maior :: Int -> Int -> Booleano maior a b | a > b = Verdadeiro | otherwise = Falso -- a é maior que b e c maior3 a b c = (maior a b) `e` (maior a c) -- maior3 7 5 6 84
  • 85.
    União Disjunta emHaskell data Number = Exact Int | Inexact Float Valores: Number = Exact Integer + Inexact Float … Exact(–2) Exact(–1) Exact 0 Exact 1 Exact 2 … … Inexact(–1.0) … Inexact 0.0 … Inexact 1.0 … Cada valor consiste de uma tag, junto ou com um valore inteiro (se a tag is Exact) ou um valor Float (se a tag é Inexact). 85
  • 86.
    Exemplo de uniãodisjunta data Number = Exact Int | Inexact Float deriving (Show) pi2 = Inexact 3.1416 rounded :: Number -> Int rounded (Exact i) = i rounded (Inexact r) = round r 86
  • 87.
    União Disjunta –Tratando erro data Maybe a = Nothing | Just a 87 Em Haskell existe um tipo de dado muito util em casos onde uma função pode não ter retorno. ●ex. buscar um elemento em uma lista type Aluno = (Int, String) busca :: Int -> [Aluno] -> Maybe String busca mat [] = Nothing busca mat ((x,y):xys) | mat == x = Just y | otherwise = busca mat xys
  • 88.
    União Disjunta union { intexact; int inexact; }; data Number = Exact Int | Inexact Float HaskellC 88
  • 89.
    Tipos Recursivos data Nat= Zero | Succ Nat data Lista = Nil | Cons Int Lista data ArvoreBin = Vazia | Nodo Int ArvoreBin ArvoreBin 89
  • 90.
    Tipos Recursivos Números naturais dataNat = Zero | Succ Nat Nat é um novo tipo com dois construtores Zero :: Nat e Succ :: Nat -> Nat 90
  • 91.
    Tipos recursivos data Nat= Zero | Succ Nat deriving (Show) soma :: Nat -> Nat -> Nat soma Zero n = n soma (Succ m) n = Succ (soma m n) mult :: Nat -> Nat -> Nat mult Zero m = Zero mult (Succ m) n = soma n (mult n m) 91
  • 92.
    Tipos Recursivos -Lista data List = Nil | Cons Int List deriving (Show) first (Cons a s) = a first Nil = error "vazio" rest (Cons a s) = s rest Nil = error "vazio" 92
  • 93.
    Polimorfismo Paramétrico C++ template <typedefT> T maior (T a, T b) { return ( (a>b)? a : b ); } public class Pair<T, S>{ public Pair(T f, S s){ first = f; second = s; } } 93 Java
  • 94.
    Polimorfismo paramétrico 94 ● Funçõesparamétricas ● Tipos de dados paramétrico
  • 95.
    ● Uma característicaimportante de Haskell é o uso de tipos paramétricos ● Muitas funções podem ser definidas em termos de tipos genéricos ● Convenção: usamos a, b, c para tipos genéricos ● Tipos paramétricos comuns, listas e tuplas length :: [a] → Int Tipos Paramétricos em Haskell Pode ser lista de inteiros, de listas .. 95
  • 96.
    data List a= Nil | Cons a List deriving (Show) first :: List a → a first (Cons a s) = a first Nil = error "vazio" rest :: List a → List a rest (Cons a s) = s rest Nil = error "vazio" data List Int = Nil | Cons Int List deriving (Show) first :: List → Int first (Cons a s) = a first Nil = error "vazio" rest :: List → List rest (Cons a s) = s rest Nil = error "vazio" Lista de inteiros Lista paramétrica 96 Tipos Paramétricos em Haskell
  • 97.
    data ArvBin a= Vazia | Nodo a (ArvBin a) (ArvBin a) deriving Show elem :: ArvBin a -> a elem Vazia = error "arvore vazia" elem (Nodo e _ _) = e esq :: ArvBin a -> ArvBin a esq Vazia = error "arvore vazia" esq (Nodo _ e _) = e dir :: ArvBin a -> ArvBin a dir Vazia = error "arvore vazia" dir (Nodo _ _ d) = d 97 Tipos Paramétricos em Haskell
  • 98.
    Definindo as funçõesde acesso diretamente na definição data ArvBin a = Vazia | Nodo { elem :: a, esq :: (ArvBin a), dir :: (ArvBin a) } deriving Show 98
  • 99.
    Restrição no polimorfismo somatodos:: [a] -> a somatodos (x:xs) = x + somatodos xs 99 Esta função pode ser aplicada a qualquer tipo ?
  • 100.
    Restrição no polimorfismo somatodos:: (Num a) => [a] -> a somatodos (x:xs) = x + somatodos xs 100 Usando “type classes A função somatodos funciona sobre qualquer “a”, desde que ele seja um Num.
  • 101.
    Type class emHaskell class Eq a where (==) :: a -> a -> Bool (/=) :: a -> a -> Bool 101 ●Uma classe é uma coleção de tipos que suportam certas operações (métodos) comuns ●Uma classe define uma assinatura, similar a uma interface
  • 102.
    Classes Básicas emHaskell Eq - tipos com igualdade Ord – tipos ordenados Show – tipos que podem ser transformados em strings Read – tipos legíveis, que pode ser convertido Num – tipos numéricos 102
  • 103.
    Instanciando type class dataPoint = Point Int Int deriving (Show, Eq, Ord, Read) instance Num Point where (+) (Point x1 y1) (Point x2 y2) = Point (x1 + x2) (y1 + y2) 103
  • 104.
    data Point =Point Int Int instance Show Point where show (Point x y) = show (x,y) Prelude> Point 4 5 > (4,5) 104 Instanciando type class ● Podemos instanciar qualquer uma das classes pré definidas, mesmo as que são deriváveis, como Read, Show ...
  • 105.
  • 106.
    Operações de entradae saída 106 Até então, vimos como usar o Haskell via ghci, mas como gerar um programa compilável? Como o Haskell consegue lidar com operações de entrada e saída ? Esse tipo de operação tem efeitos colaterais.
  • 107.
    O problema ... Umprograma em Haskell consiste num conjunto de funções, sem efeitos colaterais O objetivo de executar qqer programa é ter algum efeito colateral Tensão 107
  • 108.
    A solução IO a Otipo das ações de IO que retornam um valor do tipo a 108 Escrever programas interativos em Haskell usando tipos que fazem distinção entre expressões funcionais “puras” de ações “impuras” que podem envolver efeitos colaterais
  • 109.
    I/O em Haskell IOChar IO () O tipo das ações de IO que retornam um caracter O tipo das ações que não tem valor de retorno 109
  • 110.
    IO em Haskell:O tipo (IO a) Um valor do tipo (IO t) é uma ação que, quando realizada, pode fazer alguma forma de IO antes de devolver um resultado do tipo t. type IO a = World -> (a, World) IO a World outWorld in result::a 110
  • 111.
    Meu Primeiro Programa Ou,compile em código nátivo. module Main where main = putStrLn "Hello World!" runghc hello.hs Hello World! ghc hello.hs -o prg1 ./prg1 Hello World! 111 Para rodar interpretado use o runghc:
  • 112.
    Funções da biblioteca 112 Funçõespara escrever na tela putStr :: String -> IO () putStrLn :: String -> IO () Para ler uma linha de caracteres do teclado, podemos usar a função: getLine :: IO(String)
  • 113.
    Combinando ações Cada açãoé nessa forma: 113 Para combinar ações podemos usar a notação “do”;
  • 114.
    Meu segundo programa moduleMain where main = do input <- getLine putStrLn input 114 Lê uma entrada do usuário e imprime na tela
  • 115.
    Meu terceiro programa moduleMain where ask :: String -> IO String ask question = do putStrLn question getLine main :: IO () main = do nome <- ask "Qual eh o seu nome? " matr <- ask "Qual eh a sua matricula?" putStrLn ("Benvindo "++ nome ++ "!") putStrLn ("Sua matricula eh "++matr) 115
  • 116.
    Trabalhando com arquivos importIO import Data.Char main = do str <- readFile "input.txt" writeFile "output.txt" (map toUpper str) 116 Converte todo um arquivo texto para letras maiúsculas. A função readfile retorna uma string contendo todo o arquivo e writeFile escreve uma string em um arquivo.
  • 117.
    Funções para string 117 Funçãolines, quebra uma string pelo marcador de fim de linha lines “linha1nlinha2” = [“linha1”,linha 2] Função words, quebra uma string por separador de palavras,”espaço”. words “uma frase” = [“uma”, frase]
  • 118.
    Trabalhando com arquivos main= do str <- readFile "input.txt" print (length (words str)) print (length (lines str)) 118
  • 119.