paradigma funcional - caso de estudo haskell
DESCRIPTION
TRANSCRIPT
Prof. Sérgio Souza Costa
Paradigma FuncionalCaso de Estudo: Haskell
“Life is too short for imperative programming”
Sobre mim
Sérgio Souza CostaProfessor - UFMADoutor em Computação Aplicada (INPE)
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[1]) Criador da linguagem Lisp, segunda linguagem de programação.
Life is too short for imperative programming”
John Hughes
“
Programação funcional
● Um paradigma sem● Váriaveis
● Loops
● Ponteiros
● ...
Mudança de paradigma
PARADIGMAS DE PROGRAMAÇÃO
• Modelo, padrão ou estilo de programação suportado por linguagens que agrupam certas características comuns
Como programar ?
IMPERATIVO DECLARATIVO
PROCEDURALORIENTADO A
OBJETOSFUNCIONAL LÓGICO
É dificil programar em linguagem funcional ?
Basta abrir a cabeça
Orientação a objetos 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 )
Programação funcional é um estilo de programaçãoque permite:
- Reuso de código (composição de função)- Eliminação de bug (via imutabilidade (não existe mudança de valores de váriáveis))
Orientação a objetos Vs Funcional
Programaçao funcional
● Não existem variáveis○ Expressões
● Não existem comandos○ Funções
● Não existem efeitos colaterais○ Declarações
● Não há armazenamento○ Funções de alta ordem○ Lazy evaluation○ Recursão
● Fluxo de controle: expressões condicionais + recursão
Vantagens● Códigos suscintos e concisos
○ Menor tempo de desenvolvimento○ Manutenabilidade
● Códigos seguros● Reusabilidade● Facilidade de escrita, suporte a abstrações● Confiabilidade, segurança
Vantagens – Suscintos e Concisos
qs [] = []qs (x:xs) = qs [y | y <- xs, y < x] ++ [x] ++ qs [y | y <- xs, y >= x]
Quick sort – Haskell
Quick sort em 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;}
Quick sort em 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
Trade-offTempo de desenvolvimento
Versus
tempo de execução
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 proposito é 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(abstrai) 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 chavesAbstração de dados é o conceito chave nas linguagens funcionais modernas, tais como ML e HASKELL. Todas as operações de tipos abstratos são constantes e funções.
Polimorfismo paramétrico é um conceito chave, pois ele permite que uma função opere sobre valores de uma familia de tipos, ao invés de apenas um tipo. Na pratica, muitas funções são naturalmente polimorficas, e o polimorfismo parametrico incrementar o poder e a expressividade das linguagens funcionais
Avaliação preguiçosa e 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
Haskell na Industria
http://www.haskell.org/haskellwiki/Haskell_in_industry
Elementos básicos
● Expressões e funções● Tipos e valores● Tuplas● Listas
Expressões
● Em Haskell, construimos expressões a partir de:
● constantes
● operadores
● aplicação de funções
● (parênteses)
Expressões
● Constantes:
-3.459True'a'"hello"[1,2,4,9]
● Aplicação de funções:
even 47twice (-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
Avaliação preguiçosa
• Estratégia call-by-value --- Avalia primeiro o argumento antes de aplicar a função (Pascal, C, Java, etc).
(\x -> x+1) (2+3)= (x+1)+ 5= 5+1= 6
(\x -> x+1) (2+3)= (2+3)+1= 5+1= 6
• 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)
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 em Haskell - 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 enferidos
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
Definição de 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
Definição de funções
● A definicao de uma funçao 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 parametros de entrada da função.
● f1 :: Int → Int → Intf1 x y = x*y
Funções e constantes
● Funções generalizam as expressões através de variáveis.
-- PI
pi = 3.14159
-- area e circunferencia de circulo
circumf r = 2 * pi * r
area rad = pi * rad^2
Aplicação de funções em Haskell e na matemática
Matemáticaf (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çõ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
Considere uma função que dado dois valores, ela retorna o menor:
A estratégia para resolução do problema é com uso de uma expressão de seleção
menor x y =
se x <= y então o resultado da expressão é x
senão o resultado é y
Expressão de seleção
if <condição> then <resultado 1>
else <resultado2>
menor :: Int -> Int -> Intmenor x y = if x <= y then x
else y
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 mais elegante aos “ifs”
-- fatorial
fat :: Integer -> Integerfat 0 = 1fat n = fat (n-1) * n
Listas
● Uma lista é uma sequencia 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ãoA 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 preposiçõ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
● Um construtor de processamento de listas em linguagem de programação, a notação matemática é a sequinte:
● Outros exemplos● Por exemplo, as 10 primeiras potências de 2:[2 ^ x | x <- [1..10] ]● Todos os numeros pares maiores que 1 e menores
que 100:[ x | x <- [1..100] , par x ]
Listas por compreensão
S = [ x | x<-[0..], x^2>3 ]
Listas por compreensão
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,84,86,88,90,92,94,96,98]
Listas por compreensão
Listas com mais um gerador
Comportamento situacional em funções sobre Listas
isempty :: [a] -> Boolisempty [] = Trueisempty anythingElse = False
length [] = 0length (x : xs) = 1 + length xs
head [] = error "head []"head (x:xs) = x
Recursão
Um conceito básico em Haskell é o uso de recursão para definição de funções
length :: [a] -> Intlength [] = 0length (x : xs) = 1 + length xs
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:● Decremente um valor para cada chamada● Tome 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 [] = 0length (x : xs) = 1 + length xs
length (1 : 2 : 4 : [])
Avaliação de Funções Recursivas
length [] = 0length (x : xs) = 1 + length xs
length (1 : 2 : 4 : []) 1 + length (2 : 4 : [])
Avaliação de Funções Recursivas
length [] = 0length (x : xs) = 1 + length xs
length (1 : 2 : 4 : []) 1 + 1 + length (4 : [])
Avaliação de Funções Recursivas
length [] = 0length (x : xs) = 1 + length xs
length (1 : 2 : 4 : []) 1 + length (2 : 4 : []) 1 + 1 + length (4 : []) 1 + 1 + 1 + length []
Avaliação de Funções Recursivas
length [] = 0length (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 ordem4. Trabalhando com entrada e saída
Definições locais
Para melhor a legibilidade de um código, podemos usar a clausula “where” para fazer definiçoes visíveis somente por uma dada função.
raizes (a, b, c) = (x1,x2) where delta = sqrt ( b^2 - 4*a*c) x1 = ((-b) + delta) / (2*a) x2 = ((-b) - delta) / (2*a)
Type sinonimos
● Em Haskell, é possível criar sinonimos de tipos, ex:
type Point = (Int, Int)type Polygon = [Point]
p1 :: PointP1 = (1,4)
pol1:: Polygonpol1 = [(1,1),(1,2),(3,1),(1,1)]
Avaliação parcial
Haskell distingue entre operadores and funções:Operadores tem 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
Avaliação parcial
A função divideByTen 200 é equivalente a 200 / 10, ou (/10) 200
divideByTen :: (Floating a) => a -> a divideByTen = (/10)
Funções são valores de primeira classe
● 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
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.
twice :: (a -> a) -> a -> a twice f x = f (f x)
Map
A função map aplica uma função a todos os elementos de uma lista.
map :: (a -> b) -> [a] -> [b]
Main> map double [1,3,5,7][2,6,10,14]
Map
Map pode ser definido por recursão ou por compreensão de listas
●Ou por compreensão de lista
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
Map – Mais exemplos
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]
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 (: [])
Filter
●A função filter seleciona os elementos de uma lista que satisfazem a um predicado
filter :: (a -> Bool) -> [a] -> [a]
Main> filter even [1..10][2,4,6,8,10]
Filter
●Pode ser definido como compreensão de listas ou por recursão
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
11/4/11
Comprimindo para um único valor
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
f [] = vf (x:xs) = x � f xs
Comprimindo para um único valor
sum [] = 0sum (x:xs) = x + sum xs
product [] = 1product (x:xs) = x * product xs
and [] = Trueand (x:xs) = x && and xs
11/4/11
Comprimindo para um unico valor
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
sum = foldr (+) 0
product = foldr (*) 1
and = foldr (&&) True
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)
Composição de Funções
(f . g) x = f (g x)
> ( (*2) . (*5) ) 8> 80
Abstração de dados
Tipos enumerados (enumerated no C),Tipos cartesianos (struct no C),Uniões disjunta (union no C)Tipos recursivos
O que vimos até então...
Usamos os tipos existentes em Haskell ● Primitivos: Int, String, Bool● Compostos: Listas e tuplas
Aprendemos criar sinonimos :
type Matricula = Inttype Nome = Stringtype Salario = Doubletype Funcionario = (Matricula, Nome, Salario)
Qual o problema com os sínonimos?
11/4/11
Considerem os seguintes códigostype Matricula = Inttype Nome = Stringtype Salario = Doubletype Funcionario = (Matricula, Nome, Salario)
funcionarios :: [Funcionario]funcionarios = [(1235,"joao", 580), (256,"jose", 590)]
aumentaSalario :: Funcionario -> FuncionarioaumentaSalario (m,n,s) = (m,n,s+(0.1*s))
type Nota = Doubletype Alunos = (Matricula, Nome, Nota)
alunos :: [Alunos]alunos = [(1,"antonio", 50.6), (6,"maria", 70)]
– eu poderia aplicar aumentaSalario a alunos, pois são a mesma tupla, – apenas com nomes diferentes11/4/11
Usando tipos algébricos do Haskell
● Nós definimos um novo tipo de dado usando o palavra-chave data.
Data Funcionario = Funcionario Int String Double
type Matricula = Inttype Nome = Stringtype Salario = Double
Data Funcionario = Funcionario Matricula Nome Salario
Tipos Compostos
Os tipos algebricos 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
● Diferenças entre nome de tipos e construtor de tipos:
O nome do tipo e dos construtores não precisa ser iguais.
data InfoLivro = Livro Int String [String]
Nome do tipo
Construtor de tipo
11/4/11
Tipos algébricos
● 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
data Matricula = Matricula Int deriving (Show, Ord, Eq)
Palavra chave para derivar classes
11/4/11
Tipos algébricos – Registro
Comparação com C
struct Point {x,y: double;
};
data Point = Pt Double Double deriving (Show)
C
Haskell
Tipos algébricos – Registro
● Usando casamento de padrão para pegar um dado valor
data Point = Pt Double Double deriving (Show)
getX :: Point → Doublegetx Pt x y = x
getY :: Point → DoublegetY Pt x y = x
11/4/11
Enumerados
● Comparação com C
enum Dias {Segunda, Terça, Quarta, Quinta, Sexta}
data Dias = Segunda | Terça | Quarta| Quinta | Sexta deriving (Show)
C
Haskell
11/4/11
Tipo Booleano
● Criando e usando o seu próprio tipo booleano
data Booleano = Falso | Verdadeiro deriving (Show, Eq)
e :: Booleano -> Booleano -> Booleanoe Falso _ = Falsoe Verdadeiro b = b
maior :: Int -> Int -> Booleanomaior a b | a > b = Verdadeiro | otherwise = Falso
-- a é maior que b e cmaior3 a b c = (maior a b) `e` (maior a c)-- maior3 7 5 6
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).
11/4/11
Exemplo de união disjunta
data Number = Exact Int | Inexact Float deriving (Show)
pi2 = Inexact 3.1416 rounded :: Number -> Introunded (Exact i) = irounded (Inexact r) = round r
11/4/11
União Disjunta – Tratando erro
● Em Haskell existe um tipo de dado muito util em casos onde uma função pode nao ter retorno.●ex. buscar um elemento em uma lista
data Maybe a = Nothing | Just a
União Disjunta – Tratando erro
● Exemplo, buscando em uma lista
type Aluno = (Int, String)busca :: Int -> [Aluno] -> Maybe String
busca mat [] = Nothingbusca mat ((x,y):xys) | mat == x = Just y | otherwise = busca mat xys
União Disjunta
Comparando com a linguagem C
union {int exact;int inexact;
};
data Number = Exact Int | Inexact Float
Haskell C
Tipos Recursivos
Exemplos de tipos recursivos:
data Nat = Zero | Succ Nat
data Lista = Nil | Cons Int Lista
data ArvoreBin = Vazia | Nodo Int ArvoreBin ArvoreBin
Tipos Recursivos
Números naturais
data Nat = Zero | Succ Nat
Nat é um novo tipo com dois construtores
Zero :: Nat e Succ :: Nat -> Nat
Tipos recursivos
● Implementando as operações básicas.
data Nat = Zero | Succ Nat deriving (Show)
soma :: Nat -> Nat -> Natsoma Zero n = nsoma (Succ m) n = Succ (soma m n)
mult :: Nat -> Nat -> Natmult Zero m = Zeromult (Succ m) n = soma n (mult n m)
Tipos Recursivos - Lista
● A implementação mínima de uma lista:
data List = Nil | Cons Int Listderiving (Show)
first (Cons a s) = afirst Nil = error "vazio"
rest (Cons a s) = srest Nil = error "vazio"
Atividade
A partir da lista dada anteriormente, implemente as seguintes funções:
ultimo :: List -> Int
soma :: List -> Int
mapeia :: (Int->Int) -> List -> List – equivalente ao “map”
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; } }
Java
Polimorfismo paramétrico
● Funções paramétricas● Tipos de dados paramétrico
Tipos Paramétricos em Haskell
● 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
Pode ser lista de inteiros, de listas ..
data List a = Nil | Cons a Listderiving (Show)
first :: List a → afirst (Cons a s) = afirst Nil = error "vazio"
rest :: List a → List arest (Cons a s) = srest Nil = error "vazio"
data List Int = Nil | Cons Int Listderiving (Show)
first :: List → Intfirst (Cons a s) = afirst Nil = error "vazio"
rest :: List → List rest (Cons a s) = srest Nil = error "vazio"
Lista de inteiros Lista paramétrica
Tipos Paramétricos em Haskell
data ArvBin a = Vazia | Nodo a (ArvBin a) (ArvBin a) deriving Show
elem :: ArvBin a -> aelem Vazia = error "arvore vazia"elem (Nodo e _ _) = e
esq :: ArvBin a -> ArvBin aesq Vazia = error "arvore vazia"esq (Nodo _ e _) = e
dir :: ArvBin a -> ArvBin adir Vazia = error "arvore vazia"dir (Nodo _ _ d) = d
Tipos Paramétricos em Haskell
Definindo as funções de acesso diretamento na definição
● Equivalente a implementação anterior
data ArvBin a = Vazia | Nodo {
elem :: a, esq :: (ArvBin a),dir :: (ArvBin a)
} deriving Show
Restrição no polimorfismo
● Considere a seguinte função,● somar todos os valores de uma lista
somatodos :: [a] -> asomatodos (x:xs) = x + somatodos xs
Qual o problema nessa definição ?
Restrição no polimorfismo
● Considere a seguinte função,● somar todos os valores de uma lista
somatodos :: [a] -> asomatodos (x:xs) = x + somatodos xs
Qual o problema nessa definição ?
Restrição no polimorfismo
● Usando “type classes”
A função somatodos funciona sobre qualquer “a”, desde que ele seja um Num.
somatodos :: (Num a) => [a] -> asomatodos (x:xs) = x + somatodos xs
Type class em Haskell
●Uma classe é uma coleção de tipos que suportam certas operações (métodos) comuns●Uma classe define uma assinatura
class Eq a where (==) :: a -> a -> Bool (/=) :: a -> a -> Bool
Classes Básicas em Haskell
Eq - tipos com igualdade
Ord – tipos ordenados
Show – tipos mostráveis
Read – tipos legíveis, que pode ser convertido
Num – tipos numéricos
11/4/11
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)
● Podemos instanciar qualquer uma das classes pré definidas, mesmo as que são derivaveis, como Read, Show ...
data Point = Point Int Int
instance Show Point whereshow (Point x y) = show (x,y)
Prelude> Point 4 5> (4,5)
Instanciando type class
Hierarquia - type class
Programas e operações de entrada e saída
Operações de entrada e saída
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,
semefeitos colaterais
O objetivo de executar qqer programa é ter
algum efeito colateralTensão
A solução
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
IO a
O tipo das ações de IO que retornam um valor do tipo a
I/O em Haskell
Exemplos de IOs
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
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 aWorld out
World in
result::a
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./prg1Hello World!
Para rodar interpretado use o runghc:
Funções da biblioteca
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
Para combinar ações podemos usar a notação “do”;
Cada ação é nessa forma:
Meu segundo programa
Lê uma entrada do usuário e imprime na tela
module Main wheremain = do
input <- getLine putStrLn input
Incrementando um pouco mais
module Main where
ask :: String -> IO Stringask 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)
Lendo outros tipos, e uso de funções dentro de um IOask :: String -> IO Doubleask question = do
putStrLn question readLn
main = do a <- ask "valor de a" b <- ask "valor de b" c <- ask "valor de c" let rs = raizes (a,b,c) let r1 = fst rs let r2 = snd rs print ("raiz 1 eh " ++ (show r1) ++ ", raiz 2 eh " ++ (show r2) )
Trabalhando com arquivos
Converte todo um arquivo texto para letras maiusculas.A função readfile retorna uma string contendo todo o arquivo e writeFile escreve uma string em um arquivo.
import IOimport Data.Char main = do
str <- readFile "input.txt"writeFile "output.txt" (map toUpper str)
Funções para string
Função lines, quebra uma string pelo marcador de fim de linha
lines “linha1\nlinha2” → [“linha1”,linha 2]
Função words, quebra uma string por separador de plavras,”espaço”. words “uma frase”-> [“uma”, frase]
Trabalhando com arquivos
● Número de palavras e de linhas de um arquivo:
main = do str <- readFile "input.txt"print (length (words str))Print (length (lines str))
Trabalhando com arquivos
● Usando a função “iterative”, convertendo todas as letras de um arquivo para maiuscula.
main = interact conv where conv s = (map toUpper s)
prog1 < arquivoentr.txt > arquivosaida.txt
Trabalhando com argumentosimport System.Environment
main:: IO()main = do
args <- getArgs let arg1 = head argsprint ("o primeiro argumento eh " ++ arg1)
sergio@sergio-laptop:~$ runghc arg.hs teste"o primeiro argumento eh teste"
FIM