Download - Programação Funcional 3a. Seção de Slides Padrões Simples e Definição de Operadores em Haskell
Programação Programação FuncionalFuncional
3a. Seção de Slides
Padrões Simples e Definição de Padrões Simples e Definição de Operadores em HaskellOperadores em Haskell
2
Hoje:
• Alguns comentários e respostas das aulas passadas
• Operadores, associatividade• Padrões e casamentos• Tipos Bool, Carácteres e String e Float
3
Obs. do Lab #2Seja calcular: 7^0 + 7^1 + ... + 7^n
Logo uma função de 7^n é dada por:
pot_7 0 = 1pot_7 n = 7 * pot_7 (n-1)
Aplicar uma recursão sobre: 7^0 + 7^1 + ... + 7^n
Então:
serie_7 pot_7 0 = pot_7 0serie_7 pot_7 n = pot_7 n + serie_7 pot_7 (n-1)
Aula02> pot_7 249Aula02> serie_7 pot_7 257Aula02> :type serie_7
serie_7 :: (Num a, Num b) => (b -> a) -> b -> a
4
Correções na Apostila
--Correção na apostila do Michell
-- função ... SOMA ESPECIALs_michell f 1 = 1s_michell f n = f n + s_michell f (n-1)
(página 11, no final)
f x | x == 0 = 10| x < 0 = abs (x) | x > 0 = x - f (x-1)
Faltava também definir f ....
5
Perguntas:
write :: String -> String write x = x
Main> write "xxxx yyyy""xxxx yyyy"Main> write xxxx yyyyERROR - Undefined variable "yyyy"
Main>
6
Um pouco sobre entradas/saídas:
....putStrLn “Alo mundo”....nome_string <- getLine -- Não usa o igual... pois não é uma
-- função....
7
Comentários:ou_excl False False = Falseou_excl True True = Falseou_excl _ _ = True
Main> ou_excl True FalseTrue Main> ou_excl (4 > 6) (3 < 8)True
Obs. No uso de parênteses.... são necessários
8
Operadores
• Como visto: a linguagem Haskell contém vários operadores, como: +, -, *, /, `div`, `mod`, ^, etc.
• Operadores são infixos, o que significa que são escritos entre os seus argumentos.
• Parênteses podem ser usados em qualquer operação: (((4+8)*3)+2)
• Propriedades que auxiliam na eliminação de parênteses: associatividade e prioridade de operadores.
9
Associatividade• Uma operação op é associativa se
(x op y) op z = x op (y op z)• Operações associativas dispensam parênteses.• Ou seja, não interessa a ordem de como os cálculos
são feitos.• Uma operação não associativa é classificada como:
– associativa à esquerda; ou– associativa à direita.
10
AssociatividadeMain> 4 + 2 + 17Main> (4 - 2) - 11Main> 4 - (2 - 1)3Main> 4 - 2 - 11
Prelude> 9-(7+2)0Prelude> (9-7)+24Prelude> 9-7+24
Main> 4 + 2 + 17Main> (4 - 2) - 11Main> 4 - (2 - 1)3Main> 4 - 2 - 11
Prelude> 9-(7+2)0Prelude> (9-7)+24Prelude> 9-7+24
Adição (+) é associativa.
Adição (+) é associativa.
Subtração (-) nãoé associativa.
Subtração (-) nãoé associativa.
Subtração (-) nãoé associativa.
Subtração (-) nãoé associativa.
Subtração (-) é associativa à esquerda.
Subtração (-) é associativa à esquerda.
Finalmente, na mistura, a associativa
à esquerda
Finalmente, na mistura, a associativa
à esquerda
11
Precedência de operadores
• A associatividade define a ordem de computação de expressões envolvendo mais de uma ocorrência de um mesmo operador. Ex: 2^3^2Prelude> 2^3^2512Prelude> 2^9512
• E quando operadores diferentes são utilizados?• Por exemplo:
2+3*4 = 143^4*2 = 162
• Alguns operadores têm precedência maior do que outros.
Exponenciação é associativa à direita.
Exponenciação é associativa à direita.
12
Precedência de operadores
Main> 2 + 3 * 414Main> 2 ^ 3 * 432
Main> 2 + 3 * 414Main> 2 ^ 3 * 432
Operador * tem precedência 7, enquanto + tem prioridade 6.
Operador * tem precedência 7, enquanto + tem prioridade 6.
Operador ^ tem precedência 8.Operador ^ tem precedência 8.
13
Precedência de operadores
Main> 2 + 3 * 414Main> 2 ^ 3 * 432Main> fat 4 + 1???????????????????
Main> 2 + 3 * 414Main> 2 ^ 3 * 432Main> fat 4 + 1???????????????????
1 fat :: Int -> Int2 fat n3 | n <= 0 = 14 | otherwise = n * fat (n-1)
1 fat :: Int -> Int2 fat n3 | n <= 0 = 14 | otherwise = n * fat (n-1)
14
Precedência de operadores
Main> 2 + 3 * 414Main> 2 ^ 3 * 432Main> fat 4 + 1
25
Main> 2 + 3 * 414Main> 2 ^ 3 * 432Main> fat 4 + 1
25Aplicação de função tem
precedência máxima.
Aplicação de função temprecedência máxima.
1 fat :: Int -> Int2 fat n3 | n <= 0 = 14 | otherwise = n * fat (n-1)
1 fat :: Int -> Int2 fat n3 | n <= 0 = 14 | otherwise = n * fat (n-1)
Tabela de associatividade eprecedências pode ser encontrada
no Apêndice E do livro-texto.
Tabela de associatividade eprecedências pode ser encontrada
no Apêndice E do livro-texto.
15
Precedência de operadores
Main> fat (-1)1
Main> fat (-1)1
1 fat :: Int -> Int2 fat n3 | n <= 0 = 14 | otherwise = n * fat (n-1)
1 fat :: Int -> Int2 fat n3 | n <= 0 = 14 | otherwise = n * fat (n-1)
16
Precedência de operadores
Main> fat (-1)0Main> fat -1ERROR - Illegal class constraint in inferred type
Main> fat (-1)0Main> fat -1ERROR - Illegal class constraint in inferred type
1 fat :: Int -> Int2 fat n3 | n <= 0 = 14 | otherwise = n * fat (n-1)
1 fat :: Int -> Int2 fat n3 | n <= 0 = 14 | otherwise = n * fat (n-1)
17
Definindo Operadores• Haskell permite a definição de novos operadores.• Os nomes dos operadores são formados por:
! # $ % & * + . / < = > ? @ \ ^ | : - ~
• Restrições:– nomes não podem começar por ":"– "-" e "~" só podem ser o primeiro símbolo do nome– símbolos (e combinações) reservados:
:: => = @ \ | ^ <- ->
• Mudar associatividade ou precedência:
infix infixl infixr
Define operador como não associativo.
Define operador como não associativo.
Define operador como associativo à esquerda.
Define operador como associativo à esquerda.
Define operador como associativo à direita.
Define operador como associativo à direita.
18
Definindo Operadores1 infixl 7 &&&1 infixl 7 &&&
Define operador &&& como associativo à esquerda,
com predência 7.
Define operador &&& como associativo à esquerda,
com predência 7.
19
Definindo Operadores1 infixl 7 &&&23 (&&&) :: Int -> Int -> Int4 a &&& b5 | a > b = a6 | otherwise = b
1 infixl 7 &&&23 (&&&) :: Int -> Int -> Int4 a &&& b5 | a > b = a6 | otherwise = b
Main> 10 &&& 2020
Main> 10 &&& 2020
20
Definições com Padrões• As definições de funções vistas até agora consistem
de uma única equação.• É possível definir uma função usando várias
equações.• As equações devem especificar como a função se
comporta quando aplicada a determinados padrões.• Os padrões mais simples são variáveis e
constantes.
21
Definições com Padrões
1 .2 .
1 .2 .
totalSales 0 = sales 0totalSales n = totalSales (n-1) + (sales n)
1 totalSales :: Int -> Int2 totalSales n3 | n == 0 = sales 04 | otherwise = totalSales (n-1) + (sales n)
1 totalSales :: Int -> Int2 totalSales n3 | n == 0 = sales 04 | otherwise = totalSales (n-1) + (sales n)
• Versão anterior - uma equação condicional:
• Nova versão - usando padrões (“pattern matching”):
22
Definições com Padrões
1 .2 .
1 .2 .
totalSales 0 = sales 0totalSales n = totalSales (n-1) + (sales n)
• A primeira equação é aplicada somente ao valor 0.• A segunda se aplica a todos os outros casos.• Regra geral: utilizar a primeira equação que "casa"
com os argumentos, na ordem especificada.• Um argumento a casa com um padrão p se:
– p é uma constante e a é igual a p ; ou– p é uma variável.
23
Definições com Padrões
1 .2 .3 .
1 .2 .3 .
is Zero :: Int -> BoolisZero 0 = TrueisZero _ = False
• O padrão "_" casa com qualquer argumento (“Prolog like”).• É usado quando o valor do argumento não é necessário no
lado direito da equação.
24
Definições com Padrões
1 .2 .3 .4 .5 .6 .7 .
1 .2 .3 .4 .5 .6 .7 .
fib :: Int -> Int
fib 0 = 0fib 1 = 1fib n | n > 1 = fib (n-1) + fib (n-2) | otherwise = 0
• Exemplo envolvendo padrões e equação condicional:
25
Programando com Booleanos
• Os valores booleanos são representados pelas constantes False e True, do tipo Bool.
• Operadores:&& ("e" lógico) || ("ou" lógico) not (negação)
• Semântica dos operadores: t1 t2 t1 && t2 t1 || t2 t1 not t1 T T T T T F T F F T F T F T F T F F F F
26
Programando com Booleanos
• Uma definição para "not":
1 .2 .3 .
1 .2 .3 .
meuNot :: Bool -> BoolmeuNot True = FalsemeuNot False = True
27
Programando com Booleanos
• "ou exclusivo" - retorna True se exatamente um dos argumentos for True:
exOr :: Bool -> Bool -> Bool
exOr x y = (x || y) && not (x && y)
(Veio da definição do Ou-exclusivo... Lógica)
• Definição usando padrões:
1 .2 .
1 .2 .
exOr False x = xexOr True x = not x
28
Programando com Booleanos
• Construir uma função isZeroDay que, dado o número de um dia, retorne:– True, se o número de unidades vendidas (função sales) no
dia é zero;– False, caso contrário.
1 .2 .3 .4 .
1 .2 .3 .4 .
isZeroDay :: Int -> BoolisZeroDay n | sales n == 0 = True | otherwise = False
29
Programando com Booleanos
• Quando a expressão sales n == 0 tem valor True, a função retorna True.
• Quando a expressão sales n == 0 tem valor False, a função retorna False.
1 .2 .3 .4 .
1 .2 .3 .4 .
isZeroDay :: Int -> BoolisZeroDay n | sales n == 0 = True | otherwise = False
30
Programando com Booleanos
• Simplificação:
1 .2 .3 .4 .
1 .2 .3 .4 .
isZeroDay :: Int -> BoolisZeroDay n | sales n == 0 = True | otherwise = False
Esta função será reusada em seguida....
1 .2 .
1 .2 .
isZeroDay :: Int -> BoolisZeroDay n = (sales n == 0)
Ao invés do True ou False... A própria expressão! Humm bem elegante...
31
Programando com Booleanos
• Construir uma função zeroInPeriod que, dado o número de um dia, retorne:– True, se não foi vendida nenhuma unidade do produto em
algum dia do período 0,...,n;– False, caso contrário.
1 .2 .3 .4 .
1 .2 .3 .4 .
zeroInPeriod :: Int -> Bool
zeroInPeriod 0 = isZeroDay 0zeroInPeriod n = ????????????????
32
Programando com Booleanos
1 .2 .3 .4 .
1 .2 .3 .4 .
zeroInPeriod :: Int -> Bool
zeroInPeriod 0 = isZeroDay 0zeroInPeriod n =
... sales (n-1)sales 1sales 0 sales n
zeroInPeriod (n-1) isZeroDay n
33
Programando com Booleanos
1 .2 .3 .4 .
1 .2 .3 .4 .
zeroInPeriod :: Int -> Bool
zeroInPeriod 0 = isZeroDay 0zeroInPeriod n = zeroInPeriod (n-1) || isZeroDay n
... sales (n-1)sales 1sales 0 sales n
zeroInPeriod (n-1) ||zeroInPeriod = isZeroDay n
34
Caracteres e Strings
• Char : tipo de Haskell associado a caracteres.• Caracteres individuais são inseridos em aspas
simples. Exemplos: ´d´, ´3´.• Caracteres especiais:
´\t´ tab
´\n´ new line
´\\´ barra invertida
´\´´ aspa simples
´\"´ aspa dupla
´\97´ caractere ´a´
35
Caracteres e Strings
• Haskell utiliza a codificação padrão ASCII para caracteres.
• As funções chr e ord são usadas para conversões.
Main> chr 97´a´Main> ord ´A´65
Main> chr 97´a´Main> ord ´A´65
36
Caracteres e Strings
• Conversão de letra minúscula para maiúscula:
1 .2 .3 .4 .
1 .2 .3 .4 .
offset = ord ´A´ - ord ´a´
capitalize :: Char -> Charcapitalize ch = chr (ord ch + offset)
• Verificar se um caractere é um dígito:
1 .2 .
1 .2 .
isDigit :: Char -> BoolisDigit ch = (´0´<= ch) && (ch <= ´9´)
37
Caracteres e Strings
• Strings de caracteres pertencem ao tipo String.• São inseridas entre aspas duplas. Exemplos:
"abcdef"
"uma linha\noutra linha"
""
"O caractere \´a\´ : \97"• Strings são concatenadas usando o operador ++• Ex: “alo, ” ++ “ bom “ ++ “ dia “
38
Caracteres e Strings
• Haskell permite que novos tipos sejam criados, usando a palavra-chave type.
• O tipo String é, na realidade, uma lista de caracteres:
type String = [Char]• As operações que manipulam listas (duas aulas a
frente) podem ser usadas também para strings.• Como no Prolog: “[“ .... “]” (colchetes)... são usados
para especificar uma lista, no caso: “uma string é uma lista de carácteres”
39
Números de Ponto Flutuante
• Números de ponto flutuante são representados, em Haskell, pelos tipos Float e Double. Exemplos:
3.141592
-1.2345987.654
• Haskell usa também notação científica:
9.87654e02 = 9.87654*10 = 987.654
31415.92e-4 = 31415.92*10 = 3.141592
2
-4
40
Números de Ponto Flutuante
• Haskell oferece uma série de funções que atuam sobre números de ponto flutuante.
Main> sin (pi/2)1.0Main> 1.1 ^ 102.59374Main> 1.1 ^ 102.59374Main> 1.1 ** 10.02.59374Main> 2.5**(3.5)24.7053 Main> sqrt 21.41421
Main> sin (pi/2)1.0Main> 1.1 ^ 102.59374Main> 1.1 ^ 102.59374Main> 1.1 ** 10.02.59374Main> 2.5**(3.5)24.7053 Main> sqrt 21.41421
41
Números de Ponto Flutuante
Main> round 2.492Main> ceiling 2.493Main> floor 2.492Main> log 20.693147main> logBase 2 164.0
Main> round 2.492Main> ceiling 2.493Main> floor 2.492Main> log 20.693147main> logBase 2 164.0