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 oelsenã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 Falseif <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-elseme parece mais legível.máximo (x:xs) | (x > máximo xs) = x | otherwise = máximo xs