Conteúdos da cadeira

Expressões, avaliação e tipos em Haskell

Avaliar expressões por substituição, definir funções por equações e ler tipos predefinidos.

Markdown

Perguntar sobre esta página

ChatGPTClaudePerplexityGeminiCopiar e abrir

Envia o link e pede à IA para ler a página. No Gemini, cola a pergunta copiada.

Ver pergunta para copiar
Nesta página

Em Haskell não dizes ao computador que passos executar. Escreves equações que dizem o que cada coisa é, e a avaliação calcula o valor por substituição, como simplificar uma expressão matemática no papel. Não há variáveis que mudam nem instruções por ordem: há expressões com valor e funções que as transformam.

Avaliar é substituir

Toma esta definição:

dobra :: Int -> Int
dobra x = x * 2

A primeira linha é a assinatura de tipo: dobra recebe um Int e devolve um Int. A segunda é a equação. Avaliar dobra (3 + 1) é substituir o argumento na equação: dobra (3 + 1)(3 + 1) * 2, que dá 4 * 2, que dá 8. Este modelo mental, a avaliação por substituição, chega para prever o resultado de quase tudo nestas páginas. Guarda-o.

Funções por equações

Uma função define-se por casos, um por linha, cada um com o seu padrão de argumento:

somaQuadrados :: [Int] -> Int
somaQuadrados [] = 0
somaQuadrados (x:xs) = x^2 + somaQuadrados xs

[Int] é lista de inteiros. O padrão [] apanha a lista vazia (caso base). O padrão (x:xs) apanha uma lista não vazia e chama x à cabeça e xs à cauda. Segue somaQuadrados [1,2,3] por substituição: dá 1^2 + somaQuadrados [2,3], que dá 1 + (2^2 + somaQuadrados [3]), que dá 1 + (4 + (3^2 + somaQuadrados [])), que dá 1 + (4 + (9 + 0)), que dá 14. Repara que cada passo escolhe a equação cujo padrão encaixa, de cima para baixo. A ordem das equações importa: o caso base vem primeiro.

Isto é a recursão que já conheces de Python, mas sem if nem return: a decomposição vive nos padrões. Se te perderes, escreve a cadeia de substituições no papel até ao caso base.

Guardas para condições

Quando a escolha depende de uma condição em vez da forma do argumento, usa guardas, barras verticais lidas de cima para baixo até à primeira verdadeira:

sinal :: Int -> String
sinal n | n > 0     = "positivo"
        | n < 0     = "negativo"
        | otherwise = "zero"

otherwise é só o valor True, por isso apanha tudo o que chega ali. sinal 5"positivo", sinal 0"zero". Usa padrões para a forma dos dados e guardas para condições sobre os valores; misturar os dois na mesma função é normal.

Tipos predefinidos

Os tipos que vais usar já na primeira semana:

TipoValoresExemplo
Intinteiros de precisão fixa42, -7
Integerinteiros sem limite10^100
Doublereais em vírgula flutuante3.14
BoollógicosTrue, False
Charcarateres'a'
Stringlistas de carateres"ola"

String é só um sinónimo de [Char], por isso "ola" é a lista 'o':'l':'a':[] e todas as funções de listas funcionam em strings. Já Int contra Double é uma distinção a sério: 3 / 21.5 em Double, mas com Int precisas de div 3 2, que dá 1. Quando o GHC se queixar de tipos numa divisão, esta é quase sempre a causa.

Ver o ficheiro no GitHub

À tua maneira

Escolhe como preferes ler.

Aparência
Ajustar cores e largura
Cor de destaque do tema FEUP
Tipo de letra

Álgebra, lógica e uma ideia de cada vez.

As tuas escolhas ficam guardadas neste navegador.

Pesquisar

Escreve para pesquisar em todo o site.

para escolher · Enter para abrir · Esc para fechar

Atalhos de teclado

Clica numa tecla para a mudar. Esc cancela. Backspace desativa.

PesquisarCtrl / Cmd K

Os atalhos não interferem enquanto escreves. Tab e Enter funcionam sempre.