Paradigma Funcional - Caso de Estudo Haskell

skosta 9,392 views 119 slides Apr 18, 2012
Slide 1
Slide 1 of 119
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27
Slide 28
28
Slide 29
29
Slide 30
30
Slide 31
31
Slide 32
32
Slide 33
33
Slide 34
34
Slide 35
35
Slide 36
36
Slide 37
37
Slide 38
38
Slide 39
39
Slide 40
40
Slide 41
41
Slide 42
42
Slide 43
43
Slide 44
44
Slide 45
45
Slide 46
46
Slide 47
47
Slide 48
48
Slide 49
49
Slide 50
50
Slide 51
51
Slide 52
52
Slide 53
53
Slide 54
54
Slide 55
55
Slide 56
56
Slide 57
57
Slide 58
58
Slide 59
59
Slide 60
60
Slide 61
61
Slide 62
62
Slide 63
63
Slide 64
64
Slide 65
65
Slide 66
66
Slide 67
67
Slide 68
68
Slide 69
69
Slide 70
70
Slide 71
71
Slide 72
72
Slide 73
73
Slide 74
74
Slide 75
75
Slide 76
76
Slide 77
77
Slide 78
78
Slide 79
79
Slide 80
80
Slide 81
81
Slide 82
82
Slide 83
83
Slide 84
84
Slide 85
85
Slide 86
86
Slide 87
87
Slide 88
88
Slide 89
89
Slide 90
90
Slide 91
91
Slide 92
92
Slide 93
93
Slide 94
94
Slide 95
95
Slide 96
96
Slide 97
97
Slide 98
98
Slide 99
99
Slide 100
100
Slide 101
101
Slide 102
102
Slide 103
103
Slide 104
104
Slide 105
105
Slide 106
106
Slide 107
107
Slide 108
108
Slide 109
109
Slide 110
110
Slide 111
111
Slide 112
112
Slide 113
113
Slide 114
114
Slide 115
115
Slide 116
116
Slide 117
117
Slide 118
118
Slide 119
119

About This Presentation

No description available for this slideshow.


Slide Content

Paradigma Funcional
Caso de Estudo:
Haskell

Sobre mim
Sérgio Souza Costa
Professor - UFMA
Doutor em Computação Aplicada (INPE)


[email protected]
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
Haskell
C
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 “linha1\nlinha2”
= [“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