Programação
Funcional
Padrões Simples e Definição de
Operadores em Haskell
3a. Seção de Slides
Hoje:
• Alguns comentários e respostas das aulas
passadas
• Operadores, associatividade
• Padrões e casamentos
• Tipos Bool, Carácteres e String e Float
2
Obs. do Lab #2
Seja calcular: 7^0 + 7^1 + ... + 7^n
Logo uma função de 7^n é dada por:
pot_7 0 = 1
pot_7 n = 7 * pot_7 (n-1)
Aplicar uma recursão sobre: 7^0 + 7^1 + ... + 7^n
Então:
serie_7
serie_7
pot_7
pot_7
0 = pot_7
n = pot_7
0
n + serie_7
pot_7 (n-1)
Aula02> pot_7 2
49
Aula02> serie_7 pot_7 2
57
Aula02> :type serie_7
serie_7 :: (Num a, Num b) => (b -> a) -> b -> a
3
Correções na Apostila
--Correção na apostila do Michell
-- função ... SOMA ESPECIAL
s_michell f 1 = 1
s_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 ....
4
Perguntas:
write :: String -> String
write x = x
Main>
"xxxx
Main>
ERROR
write "xxxx yyyy"
yyyy"
write xxxx yyyy
- Undefined variable "yyyy"
Main>
5
Um pouco sobre entradas/saídas:
....
putStrLn “Alo mundo”
....
nome_string <- getLine -- Não usa o igual... pois não é uma
-- função
....
6
Comentários:
ou_excl False False =
ou_excl True True
=
ou_excl _
_
=
False
False
True
Main> ou_excl True False
True
Main> ou_excl (4 > 6) (3 < 8)
True
Obs. No uso de parênteses.... são necessários
7
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.
8
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.
9
Associatividade
Main>
7
Main>
1
Main>
3
Main>
1
4 + 2 + 1
(4 - 2) - 1
Adição (+) é
associativa.
4 - (2 - 1)
4 - 2 - 1
Subtração (-) é
associativa à esquerda.
Prelude> 9-(7+2)
Subtração (-) não
0
Prelude> é
(9-7)+2
associativa.
4
Finalmente, na
Prelude> 9-7+2
mistura, a associativa
4
à esquerda
10
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^2
Prelude> 2^3^2
512
Exponenciação é
Prelude> 2^9
associativa à direita.
512
• E quando operadores diferentes são utilizados?
• Por exemplo:
2+3*4 = 14
3^4*2 = 162
• Alguns operadores têm precedência maior do que outros.
11
Precedência de operadores
Main> 2 + 3 * 4
14
Main> 2 ^ 3 * 4
32
Operador * tem precedência 7,
enquanto + tem prioridade 6.
Operador ^ tem precedência 8.
12
Precedência de operadores
Main> 2 + 3 * 4
14
Main> 2 ^ 3 * 4
32
Main> fat 4 + 1
???????????????????
1
2
3
4
fat
fat
|
|
:: Int -> Int
n
n <= 0
= 1
otherwise
= n * fat (n-1)
13
Precedência de operadores
Main> 2 + 3 * 4
14
Main> 2 ^ 3 * 4
32
Main> fat 4 + 1
25
Aplicação de função tem
precedência máxima.
Tabela de associatividade e
precedências pode ser encontrada
no Apêndice E do livro-texto.
1
2
3
4
fat
fat
|
|
:: Int -> Int
n
n <= 0
= 1
otherwise
= n * fat (n-1)
14
Precedência de operadores
Main> fat (-1)
1
1
2
3
4
fat
fat
|
|
:: Int -> Int
n
n <= 0
= 1
otherwise
= n * fat (n-1)
15
Precedência de operadores
Main> fat (-1)
0
Main> fat -1
ERROR - Illegal class constraint in
inferred type
1
2
3
4
fat
fat
|
|
:: Int -> Int
n
n <= 0
= 1
otherwise
= n * fat (n-1)
16
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 ":"
operador
Define
como
operador
Define
não
como
operador
– "-" e Define
"~" só podem
ser o primeiro
símbolo
do nome como
associativo.
associativo
àassociativo
esquerda. à direita.
– símbolos (e combinações)
reservados:
:: => =
@ \ | ^ <- ->
• Mudar associatividade ou precedência:
infix infixl infixr
17
Definindo Operadores
1
infixl 7 &&&
Define operador &&& como
associativo à esquerda, com
predência 7.
18
Definindo Operadores
1
2
3
4
5
6
infixl 7 &&&
(&&&) :: Int -> Int -> Int
a &&& b
| a > b
= a
| otherwise
= b
Main> 10 &&& 20
20
19
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.
20
Definições com Padrões
• Versão anterior - uma equação condicional:
1
2
3
4
totalSales :: Int -> Int
totalSales n
| n == 0
= sales 0
| otherwise
= totalSales (n-1) + (sales n)
• Nova versão - usando padrões (“pattern matching”):
1 .totalSales 0 = sales 0
2 .totalSales n = totalSales (n-1) + (sales n)
21
Definições com Padrões
1 .totalSales 0 = sales 0
2 .totalSales 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.
22
Definições com Padrões
• 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.
1 .is Zero :: Int -> Bool
2 .isZero 0
= True
3 .isZero _
= False
23
Definições com Padrões
• Exemplo envolvendo padrões e equação
condicional:
1
2
3
4
5
6
7
.fib
.
.fib
.fib
.fib
. |
. |
:: Int -> Int
0 = 0
1 = 1
n
n > 1
otherwise
= fib (n-1) + fib (n-2)
= 0
24
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
T
T
F
F
t2
T
F
T
F
t1 && t2
T
F
F
F
t1 || t2
T
T
T
F
t1
T
F
not t1
F
T
25
Programando com Booleanos
• Uma definição para "not":
1 .meuNot :: Bool -> Bool
2 .meuNot True = False
3 .meuNot False = True
26
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 .exOr False x = x
2 .exOr True x = not x
27
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
.isZeroDay :: Int -> Bool
.isZeroDay n
. | sales n == 0
= True
. | otherwise
= False
28
Programando com Booleanos
1
2
3
4
.isZeroDay :: Int -> Bool
.isZeroDay n
. | sales n == 0
= True
. | otherwise
= False
• 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.
29
Programando com Booleanos
1
2
3
4
.isZeroDay :: Int -> Bool
.isZeroDay n
. | sales n == 0
= True
. | otherwise
= False
Esta função será reusada em seguida....
• Simplificação:
1 .isZeroDay :: Int -> Bool
2 .isZeroDay n = (sales n == 0)
Ao invés do True ou False... A própria
expressão! Humm bem elegante...
30
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
.zeroInPeriod :: Int -> Bool
.
.zeroInPeriod 0 = isZeroDay 0
.zeroInPeriod n = ????????????????
31
Programando com Booleanos
1
2
3
4
.zeroInPeriod :: Int -> Bool
.
.zeroInPeriod 0 = isZeroDay 0
.zeroInPeriod n =
sales 0
sales 1
...
sales (n-1)
zeroInPeriod (n-1)
sales n
isZeroDay n
32
Programando com Booleanos
1
2
3
4
.zeroInPeriod :: Int -> Bool
.
.zeroInPeriod 0 = isZeroDay 0
.zeroInPeriod n = zeroInPeriod (n-1) || isZeroDay n
sales 0
sales 1
...
sales (n-1)
zeroInPeriod = zeroInPeriod (n-1)
||
sales n
isZeroDay n
33
Caracteres e Strings
• Char : tipo de Haskell associado a caracteres.
• Caracteres individuais são inseridos em aspas
simples. Exemplos: ´d´, ´3´.
• Caracteres especiais:
´\t´
´\n´
´\\´
´\´´
´\"´
´\97´
tab
new line
barra invertida
aspa simples
aspa dupla
caractere ´a´
34
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
35
Caracteres e Strings
• Conversão de letra minúscula para maiúscula:
1
2
3
4
.offset = ord ´A´ - ord ´a´
.
.capitalize :: Char -> Char
.capitalize ch = chr (ord ch + offset)
• Verificar se um caractere é um dígito:
1 .isDigit :: Char -> Bool
2 .isDigit ch = (´0´<= ch) && (ch <= ´9´)
36
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 “
37
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”
38
Números de Ponto Flutuante
• Números de ponto flutuante são representados, em
Haskell, pelos tipos Float e Double. Exemplos:
3.141592
-1.2345
987.654
• Haskell usa também notação científica:
2
9.87654e02 = 9.87654*10
= 987.654
-4
31415.92e-4 = 31415.92*10 = 3.141592
39
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.0
Main> 1.1 ^ 10
2.59374
Main> 1.1 ^ 10
2.59374
Main> 1.1 ** 10.0
2.59374
Main> 2.5**(3.5)
24.7053
Main> sqrt 2
1.41421
40
Números de Ponto Flutuante
Main> round 2.49
2
Main> ceiling 2.49
3
Main> floor 2.49
2
Main> log 2
0.693147
main> logBase 2 16
4.0
41
Download

Visualizar - GEOCITIES.ws