Observações
Cheat sheet
https://hackage.haskell.org/package/CheatSheet-1.7/src/CheatSheet.pdf
Todo if
tem um then
e um else
- Diferentemente de outras linguagens, onde o
if
é usado para determinar se uma computação deve acontecer e oelse
é um atalho para quando há duas opções, e portanto oelse
não é necessário, em Haskell oif
é usado para determinar qual computação deve acontecer, ou seja, sempre há duas opções.
if (x > 3) //If sem else: compila.
y = "maior"; //Se x <= 3, y continua com o valor anterior, seja qual for.
let y = if x > 3
then "maior" -- If sem else: não compila! Qual o valor de `y` se `x <= 3`?
Por isso o if
do Haskell deve ser comparado ao operador ternário do C, não com o if
.
y = x > 3? "maior": "menor";
let y = if x > 3 then "maior" else "menor"
Linha do erro
As vezes o compilador aponta uma linha como tendo um erro e você olha para a tal linha por horas sem entender o que há de errado. Talvez ela não esteja errada! Acontece que o compilador tenta ao máximo usar o seu código, e por isso às vezes passa por cima de erros e só para quando não dá mais para interpretar o arquivo. Por isso, quando o compilador apontar um erro em uma linha, sempre considere as linhas anteriores também como potencialmente problemáticas.
Falta de parênteses
Prelude> 4/2*2
4.0
Prelude> 4/(2*2)
1.0
Parênteses desnecessários
((b1+b2)/2) * h
->(b1+b2)/2 * h
- não há dúvida para o compilador que a divisão deve ocorrer primeiro, pois os operadores tem a mesma precedência e ambos são associativos à esquerda.
-
sqrt ((b*b)+ (c*c))
-> sqrt (b*b + c*c)- não há dúvida para o compilador que a divisão deve ocorrer primeiro, pois os operadores tem precedências diferentes.
-
Informação sobre precedência e associatividade pode ser derivadas via
:info
.Prelude> :info * type Num :: * -> Constraint class Num a where ... (*) :: a -> a -> a ... infixl 7 * -- Infixo com associatividade a esquerda (l) e Precedência 7. Prelude> :info / type Fractional :: * -> Constraint class Num a => Fractional a where (/) :: a -> a -> a ... infixl 7 / -- Infixo com associatividade a esquerda (l) e Precedência 7. Prelude> :info + type Num :: * -> Constraint class Num a where (+) :: a -> a -> a ... infixl 6 + -- Infixo com associatividade a esquerda (l) e Precedência 6.
Quebra de linha e indentação
-
maiorDeTres a b c = if a > b && a > c then a else if b > a && b > c then b else c
- Difícil leitura.
- Quebrar linhas.
-
estaoOrdenados a b c = if (a > b && b > c) then True else False
if <cond> then True else False
-><cond>
estaoOrdenados a b c = a > b && b > c
-
sqrt((a^2) + (b^2))
- Parênteses só são necessários para deixar explícito o que é parâmetro.
sqrt((a^2) + (b^2))
- Funções e parâmetros são separados por espaço.
sqrt ((a^2) + (b^2))
sqrt ((a^2) + (b^2))
- Operadores tem precedências; potência tem precedência maior que adição
sqrt (a^2 + b^2)
sqrt a^2 + b^2
- Funções tem precedência sobre operadores.
sqrt a^2 + b^2 == (sqrt a^2) + b^2
Exceções
Para indicar uma condição de erro, use "error". Por exemplo, em uma solução eu encontrei o seguinte | otherwise = (99, "error")
mas o ideal seria |otherwise = error "mensagem de erro"
.
Caso base na recursão
-
Toda recursão deve ter um caso base, senão a recursão não para.
-
No seguinte trecho, só temos dois casos. Um
if-then-else
me parece mais legível.máximo (x:xs) | (x > máximo xs) = x | otherwise = máximo xs