Introdução a Haskell
Published:
Operadores Matemáticos
A linguagem Haskell possui diversos operadores matemáticos, conforme descritos a seguir em forma de funções:
soma x y = x + y
subtrai x y = x - y
multiplica x y = x * y
divide x y = x / y
divideInt1 x y = x `div` y
divideInt1 x y = x `quot` y
resto1 x y = x `mod` y
resto2 x y = x `rem` y
elevado1 x y = x ^ y
elevado2 x y = x ** y
A diferença entre div
e quot
é que o primeiro arredonda o resultado na direção de infinito negativo, enquanto o segundo arredonda na direção de zero. Essa mesma diferença é observada entre mod
e rem
.
Os operadores de potência diferem quanto ao expoente, o operador ^
recebe apenas expoentes inteiros, enquanto **
aceita expoentes reais.
Além desses operadores, o Haskell também possui as funções log
para logaritmo natural, logBase base
para logaritmo na base base
, sqrt
para raíz quadrada, exp
para exponencial, abs
para valor absoluto. Também possui as funções trigonométricas sin
, cos
, tan
, asin
, acos
, atan
, e funções de arredondamento truncate
, round
, floor
, ceiling
.
Notem que a ordem das operações em uma expressão matemática segue uma ordem de precedência na avaliação, considere a seguinte expressão:
\[1 + x * 3\]A ordem que avaliamos as operações fazem diferença! Se primeiro calcularmos a soma de \(1\) com \(x\) e somente após multiplicarmos por \(3\) resultará em um valor diferente caso resolvamos realizar a multiplicação primeiro. Na matemática, para evitar ambiguidade utilizamos parênteses:
\[1 + (x * 3)\]Em linguagem de programação, além do uso de parênteses, a linguagem define a priori a prioridade de cada operador e a ordem de execução. Considere o seguinte algoritmo:
f x = 1 + x * 3
g x = (1 + x) * 3
As funções f
e g
resultam em valores diferentes, no Haskell a prioridade é definida por um valor numérico de \(0\) a \(9\), em que \(9\) é a precedência mais alta e a ordem de avaliação: esquerda, direita, indiferente, que determina se a expressão é avaliada da esquerda para direita ou da direita para a esquerda.
No prompt de comando ou terminal execute o ghci para entrarmos no modo interativo, nele digite o comando :info (+)
, a saída será:
:info (+)
class Num a where
(+) :: a -> a -> a
...
-- Defined in ‘GHC.Num’
infixl 6 +
As primeiras linhas indicam que o operador +
pode ser aplicado para qualquer valor numérico (Num
) e recebe dois valores, retornando um novo valor (a -> a -> a
). Ao final, a precedência e associatividade do operador é revelado: infixl
, indicando que a expressão é avaliada da esquerda para direita e 6
indicando que a precedência é no nível 6.
Comparando com o operador ^
(:info (^)
) temos:
:info (^)
(^) :: (Num a, Integral b) => a -> b -> a -- Defined in ‘GHC.Real’
infixr 8 ^
Indicando que a prioridade desse operador é 8
e ele é avaliado da direita para a esquerda. Considere a expressão:
O Haskell irá avaliar a expressão na seguinte sequência:
3 + 4 ^ (5 + 6)
3 + 4 ^ 11
3 + 4194304
4194307
Exercício 01: Calcule a razão áurea dada pela expressão \(\frac{1 + \sqrt{5}}{2}\)
aurea = (1 + sqrt 5) / 2
Exercício 02: Defina a função para calcular a entropia de um sistema binário dada por \(-p \cdot log(p) - (1-p) \cdot log(1-p)\), sendo que o logaritmo é na base 2.
entropia p = -p * (logBase 2 p) - (1 - p) * (logBase 2 (1-p))
Nas próximas aulas aprenderemos a tornar essas funções mais simples e concisas.
Exercício 03: Defina uma função para calcular a distância quadrática entre um ponto (definido pelos valores de x e y) e o centro de uma circunferência (definida pelos valores cx e cy), dada pela expressão \((cx - x)^2 + (cy - y)^2\).
distanciaQuad x y cx cy = (cx - x)^2 + (cy - y)^2
Operadores Lógicos e Relacionais
Considere o seguinte problema: dada a distância quadrática entre um ponto e o centro de uma circunferência, determine se ele está dentro ou fora da circunferência de raio r
.
Para resolver tal problema basta verificar se a distância quadrática entre o ponto e o centro é menor ou igual ao quadrado do raio (dentro da circunferência) ou maior (fora).
No Haskell temos os operadores relacionais que verificam a relação entre os valores das expressões:
igual x y = x == y
diferente x y = x /= y
maior x y = x > y
menor x y = x < y
maiorIgual x y = x >= y
menorIgual x y = x <= y
Esses operadores retorna True
(verdadeiro) ou False
(falso). Nosso problema poderia ser resolvido como:
estaDentro x y cx cy r = (distanciaQuad x y cx cy) <= r^2
Além disso, o resultado dessas operações podem ser combinadas com operadores lógicos: &&
(e lógico), ||
(ou lógico) e not
(não lógica), que funcionam da mesma forma que os operadores algébricos:
True && True == True
True && False == False
True || False == True
False || False == False
not True == False
Exercício 04: determine se um ano é bissexto dado que todo ano bissexto ou é múltiplo de 400 ou é múltiplo de 4 mas não de 100. Verifique a ordem de precedência dos operadores e a necessidade do uso de parênteses.
bissexto ano = (ano `rem` 400 == 0) || ((ano `rem` 4 == 0) && (ano `rem` 100 /= 0))
Na próxima aula aprenderemos sobre os tipos nativos de dados do Haskell, mais alguns operadores e detalharemos o conceito de funções.