Haskell em 10 minutos
From HaskellWiki
Contents |
1 Introdução
Haskell é uma linguagem de programação funcional (isto é, tudo é feito através de definições e chamadas de função), de tipagem estática e implícita (tipos são conferidos pelo compilador, mas você não precisa declará-los), e lazy (nada é feito até que seja necessário). As outras linguagens mais parecidas provavelmente são da família de ML (que não são lazy).
O compilador mais popular de Haskell é o GHC. Você pode baixá-lo de http://www.haskell.org/ghc/download.html . Existem executáveis do GHC disponíveis para GNU/Linux, FreeBSD, MacOS, Windows, e Solaris. quando você tiver o GHC instalado, vão ter dois programas de nosso interesse: ghc e ghci. O primeiro compila código Haskell para executáveis. O segundo é um interpretador interativo que permite que você escreva código Haskell e tenha o retorno imediato.
2 Expressões simples
Você pode digitar várias expressões matemáticas no ghci e ter uma resposta. Prelude> é o prompt padrão do GHCi.
Prelude> 3 * 5 15 Prelude> 4 ^ 2 - 1 15 Prelude> (1 - 5)^(3 * 2 - 4) 16Strings são escritas em "aspas." Você pode concatená-las com
Prelude> "Oi" "Oi" Prelude> "Oi" ++ ", Haskell" "Oi, Haskell"
Chamadas a funções são feitas colocando os argumentos diretamente após o nome da função. Não são usados parênteses nas chamadas:
Prelude> succ 5 6 Prelude> truncate 6.59 6 Prelude> round 6.59 7 Prelude> sqrt 2 1.4142135623730951 Prelude> not (5 < 3) True Prelude> gcd 21 14 7
3 O console
Ações de I/O (entrada e saída) podem ser usadas para ler e escrever no console. Algumas delas que são comuns incluem:
Prelude> putStrLn "Oi, Haskell!" Oi, Haskell! Prelude> putStr "Sem quebra de linha!" Sem quebra de linha! Prelude> print (5 + 4) 9 Prelude> print (1 < 2) TrueAs funções
Prelude> do { putStr "2 + 2 = " ; print (2 + 2) }
2 + 2 = 4
Prelude> do { putStrLn "ABCDE" ; putStrLn "12345" }
ABCDE
12345
Leituras podem ser veitas com Prelude> do { n <- readLn ; print (n^2) }
4
16
(O 4 foi digitado, e 16 o resultado.)
Existe uma outra forma de se escrever blocosmain = do putStrLn "Quanto é 2 + 2?" x <- readLn if x == 4 then putStrLn "Você acertou!" else putStrLn "Você errou!"
(Nota: Não indente com tabs se você estiver usando o layout. Isso tecnicamente funcionaria se seus tabs tiverem a largura de 8 espaços, mas é uma má idéia. Também não use fontes proporcionais -- o que aparentemente algumas pessoas fazem, mesmo quando programando!)
4 Tipos simples
Até agora, nenhuma declaração de tipo foi mencionada. Isso se deve ao fato de Haskell fazer inferência de tipos. Você normalmente não precisa declarar tipos a menos que você queira. Se você quiser declarar um tipo, usa-sePrelude> 5 :: Int 5 Prelude> 5 :: Double 5.0
Tipos (e typeclasses, discutidas depois) sempre começam com uma letra maiúscula em Haskell. Variáveis sempre começam com letras minúsculas. Essa é uma regra da linguagem, e não uma convenção de nomenclatura.
Você também pode perguntar ao ghci que tipo ele inferiu para algo. Isso é útil porque geralmente você não precisa declarar tipo algum.
Prelude> :t True True :: Bool Prelude> :t 'X' 'X' :: Char Prelude> :t "Oi, Haskell!" "Oi, Haskell!" :: [Char](Se você percebeu,
As coisas ficam mais interessantes com números.
Prelude> :t 42 42 :: (Num t) => t Prelude> :t 42.0 42.0 :: (Fractional t) => t Prelude> :t gcd 15 20 gcd 15 20 :: (Integral t) => t
Esses tipos usam "type classes". Elas significam:
- podem ser usados como qualquer tipo numérico. (Isso é porque eu pude declarar42tanto como5ouIntantes.)Double
- pode ser qualquer tipo fracionário, mas não integral.42.0
- (que é uma chamada de função, incidentalmente) pode ser qualquer tipo integral, mas não fracionário.gcd 15 20
Existem cinco tipos numéricos no "prelúdio" do Haskell (Prelude, a parte da biblioteca padrão que vem sem precisar importar nada):
- é um inteiro com ao menos 30 bits de precisão.Int
- é um inteiro com precisão ilimitada.Integer
- é um número de ponto flutuante de precisão simples.Float
- é um número de ponto flutuante de precisão dupla.Double
- é um tipo fracionário, sem erro de arredondamento.Rational
Sumarizando isso tudo,
Prelude> gcd 42 35 :: Int
7
Prelude> gcd 42 35 :: Double
<interactive>:1:0:
No instance for (Integral Double)
O último tipo que vale a pena mencionar aqui é Prelude> () () Prelude> :t () () :: ()Você pode ver isso de forma similar a palavra-chave void na família das linguagens C. Você pode retornar
5 Informação estruturada
Tipos básicos podem ser combinados facilmente de duas formas: listas, que vão entre [colchetes], e tuplas, que vão entre (parênteses).
Listas são usadas para armazenar vários valores do mesmo tipo.
Prelude> [1, 2, 3] [1,2,3] Prelude> [1 .. 5] [1,2,3,4,5] Prelude> [1, 3 .. 10] [1,3,5,7,9] Prelude> [True, False, True] [True,False,True]
Strings nada mais são que listas de caracteres.
Prelude> ['O', 'i', ',', ' ', 'H', 'a', 's', 'k', 'e', 'l', 'l', '!'] "Oi, Haskell!"O operador
Prelude> 'C' : ['O', 'i'] "COi"
Tuplas armazenam um número fixo de valores, que podem ter tipos diferentes.
Prelude> (1, True) (1,True) Prelude> zip [1 .. 5] ['a' .. 'e'] [(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e')]O último exemplo usou
Os tipos são provavelmente o que você já espera.
Prelude> :t ['a' .. 'c']
['a' .. 'c'] :: [Char]
Prelude> :t [('x', True), ('y', False)]
[('x', True), ('y', False)] :: [(Char, Bool)]
Listas são usadas bastante em Haskell. Existem várias funções que fazem coisas legais com elas.
Prelude> [1 .. 5] [1,2,3,4,5] Prelude> map (+ 2) [1 .. 5] [3,4,5,6,7] Prelude> filter (> 2) [1 .. 5] [3,4,5]
Existem duas funções legais para pares ordenados (tuplas de dois elementos):
Prelude> fst (1, 2) 1 Prelude> snd (1, 2) 2 Prelude> map fst [(1, 2), (3, 4), (5, 6)] [1,3,5]
Veja também como trabalhar com listas.
6 Definições de função
Nós escrevemos a definição de uma ação de I/O anteriormente, chamadamain = do putStrLn "Quanto é 2 + 2?" x <- readLn if x == 4 then putStrLn "Você acertou!" else putStrLn "Você errou!"
module Main where factorial n = if n == 0 then 1 else n * factorial (n - 1) main = do putStrLn "Quanto é 5! ?" x <- readLn if x == factorial 5 then putStrLn "Você acertou!" else putStrLn "Você errou!"
Compile de novo o código usando ghc --make Test.hs. E,
$ ./Test Quanto é 5! ? 120 Você acertou!Isso é uma função. Assim como as funções incluídas na biblioteca padrão da linguagem, ela pode ser chamada com
Agora pergunte qual é o tipo ao ghci.
$ ghci Test.hs << banner do GHCi >> Ok, modules loaded: Main. Prelude Main> :t factorial factorial :: (Num a) => a -> aTipos de função são escritos com o tipo do argumento, então
A função factorial pode ser simplificada, re-escrita com análise de caso.
factorial 0 = 1 factorial n = n * factorial (n - 1)
7 Sintaxe conveniente
Existem mais algumas coisas que ajudam na sintaxe.
secsToWeeks secs = let perMinute = 60 perHour = 60 * perMinute perDay = 24 * perHour perWeek = 7 * perDay in secs / perWeek
classify age = case age of 0 -> "newborn" 1 -> "infant" 2 -> "toddler" _ -> "senior citizen"
8 Usando bibliotecas
Tudo usado até agora neste tutorial é parte do módulo Prelude, que é o conjunto de funções Haskell que estão sempre disponíveis em qualquer programa.
O melhor caminho para se tornar um programador Haskell bem produtivo (além de prática!) é conhecer as outras bibliotecas que fazem o que você precisa. A documentação da biblioteca padrão está em http://haskell.org/ghc/docs/latest/html/libraries/. Lá tem módulos com:
- Estruturas de dados úteis
- Programação paralela e concorrente
- Bibliotecas gráficas e de GUI
- Redes, POSIX e outras coisas de nível de sistema
- Duas frameworks de testes, QuickCheck e HUnit
- Expressões regulares e parsers preditivos
- Mais ...
module Main where import qualified Data.Map as M errorsPerLine = M.fromList [ ("Carlos", 472), ("Dani", 100), ("Saulo", -5) ] main = do putStrLn "Quem é você?" name <- getLine case M.lookup name errorsPerLine of Nothing -> putStrLn "Eu não te conheço." Just n -> do putStr "Erros por linha: " print n
Se você precisa de algo que não exista na biblioteca padrão, tente procurar em http://hackage.haskell.org/packages/hackage.html ou na página de aplicações e bibliotecas desta wiki. Essa é uma coleção de muitas bibliotecas diferentes escritas por muita gente. Uma vez que você tenha uma biblioteca, extraia ela, vá ao seu diretório e faça o seguinte para instalar:
runhaskell Setup configure runhaskell Setup build runhaskell Setup install
Em um sistema UNIX, você provavelmente vai precisar ser root para fazer a última parte.
9 Tópicos que excedem nosso limite de 10 minutos
- Advanced data types|Tipos de dados avançados
- Listas aritméticas
- Comprehensions em listas
- Sinônimos de tipagem
- data vs newtype (and here)
- Type classes e instâncias
- Sintaxe avançada
- Funções avançadas
- Monads
- I/O em arquivos
- Ler arquivos
- Gravar arquivos
