Dicas de desenvolvimento Haskell
Nessa área do Twiki são postadas alguamas dicas para o desenvolvimento Haskell, que podem ser úteis para quem está se familiarizando com essa linguagem.
Ferramentas
Compiladores e/ou interpretadores sugeridos:
- ghc:Acredito que seja a implementação de referência das bibliotecas Haskell (isso porque alguns pacotes são validos apenas para o ghc). Um conjunto de ferramentas auxiliares é disponibilizado após a instalação (ghci, runhaskell, ghc-pkg, etc.)
- hugs: Na versão Windows, oferece um interpretador um pouco mais amigável que o ghc interpreter. Útil para quem deseja dar os primeiros passos na linguagem. A minha conclusão é que o ghc oferece uma solução mais estável para a linguagem Haskell.
Ambiente de desenvolvimento:
- Functional Programming Plugin: Plugin eclipse para linguagens funcionais. Apenas o suporte a linguagem Haskell foi avaliado. Razoável, principal utilidade é o editor sensível a sintaxe.
Entrada e Saída em Haskell
(conteúdo baseado em
Yet Another Haskell Tutorial Hal Daumé III)
Não existe uma solução "elegante" para representar operações de entrada e saída como funçõe (de forma simples, tais operações apresentam efeitos colaterais). Por exemplo, qual o tipo de retorno para uma função responsável por uma
operação que imprime uma String na tela? Poderíamos imaginar "()" como primeira alternativa. Por outro lado, devido à propriedade de transparência referencial, seria possível substituir tal função por qualquer outra definida como f _ = (). Obviamente, o resultado não seria o esperado.
A solução para representar
operações de entrada em saída como
ações (talvez Monads fosse um termo mais correto aqui) foi proposta por Phil Wadler. Ações são nomeadas e têm tipos bem definidos. Por exemplo, a ação que imprime uma String na tela é definida como:
putStrLn :: String -> IO ()
Tal ação recebe uma String como argumento e retorna o tipo
IO (). Sintaticamente, esse tipo de retorno é o que diferencia uma função de uma ação. Quando a ação é avaliada, seu retorno é (). Agora considere:
getLine :: IO String
getLine é uma ação que retorna um valor String.
Um programa Haskell é uma única ação que é executada quando o programa compilado é executado. Dessa forma, os compiladores esperam que a funação
main tenha tipo IO que retorna (). Não é comum executar ações diretamente. Por outro lado, as ações podem ser combinadas (utilizando a notação
do) no corpo da função
main. A construção
do oferece os mecanismos para a composição de ações.
Por exemplo, tente executar o seguinte programa, definido em um módulo Main (ghc --make Main.hs)
main = do
putStrLn "Por favor, entre seu nome: "
nome <- getLine
putStrLn ("Ola, " ++ nome ++ ", como voce vai?")
No exemplo, três ações são sequenciadas: uma impressão na tela, seguida de uma leitura da entrada padrão, seguida de outra impressão na tela. A construção "<-" é usada para expor o resultado de uma ação. Como um exemplo mais real, considere o parser de dois arquivos XML (utilizando a biblioteca HXT). O resultado do parser é atribuído aos identificadores x e y.
main :: IO ()
main = do
[x] <- runX ( xunpickleDocument xpUseCaseModel [ (a_validate,v_0)
, (a_trace, v_1)
, (a_remove_whitespace,v_1)
, (a_preserve_comment, v_0)
] "completo.xml" )
[y] <- runX ( xunpickleDocument xpFeature [ (a_validate,v_0)
, (a_trace, v_1)
, (a_remove_whitespace,v_1)
, (a_preserve_comment, v_0)
] "feature-model.xml" )
...
Apesar de não ter sido destacado, as operações de IO são suportadas pelo conceito de
Monads. Muitas das ações de entrada e saída estão disponiveis na biblioteca IO. Algumas definições dessa biblioteca são apresentadas abaixo:
data IOMode = ReadMode | WriteMode | AppendMode | ReadWriteMode
openFile :: FilePath -> IOMode -> IO Handle
hClose :: Handle -> IO ()
hIsEOF :: Handle -> IO Bool
hGetChar :: Handle -> IO Char
hGetLine :: Handle -> IO String
hGetContents :: Handle -> IO String
getChar :: IO Char
getLine :: IO String
getContents :: IO String
hPutChar :: Handle -> Char -> IO ()
hPutStr :: Handle -> String -> IO ()
hPutStrLn :: Handle -> String -> IO ()
putChar :: Char -> IO ()
putStr :: String -> IO ()
putStrLn :: String -> IO ()
readFile :: FilePath -> IO String
writeFile :: FilePath -> String -> IO ()
FilePath é apenas um sinônimo para o tipo String. A ação
hGetContents lê todo o conteúdo de um arquivo. Ações que começam com "h" (hGetLine, hPutStrLn) fazem acesso de leitura / escrita em arquivos. Ações similares, que não iniciam com "h" (getLine, putStrLn) fazem acesso nos dispositivos de entrada e saída padrão.
Instalação de Pacotes (Hackage)
Muitas bibliotecas Haskell estão disponíveis como pacotes
Cabal. Esse é um formato usado para empactoamento de bibliotecas e programas Haskell. O resultado é que tais "componentes" podem ser compilados em diferentes plataformas. A forma básica de instalar um pacote disponibilizado no formato
Cabal consiste em:
- Fazer o download do pacote. Muitos pacotes são disponibilizados no banco de dados de pacotes Haskell
- Descompactar o arquivo que foi feito o download
- Usar a ferramenta runhaskell para configurar, preparar o build e instalar. Abaixo um exemplo desses passos para instalar o pacote Happy
$ runhaskell Setup.lhs configure
Configuring happy-1.17...
$ runhaskell Setup.lhs build
Preprocessing executables for happy-1.17...
Building happy-1.17...
[ 1 of 18] Compiling Set ( src/Set.hs, dist/build/happy/happy-tmp/Set.o )
[ 2 of 18] Compiling NameSet ( src/NameSet.hs, dist/build/happy/happy-tmp/NameSet.o )
[ 3 of 18] Compiling Target ( src/Target.lhs, dist/build/happy/happy-tmp/Target.o )
[ 4 of 18] Compiling AbsSyn ( src/AbsSyn.lhs, dist/build/happy/happy-tmp/AbsSyn.o )
...
[18 of 18] Compiling Main ( src/Main.lhs, dist/build/happy/happy-tmp/Main.o )
$ runhaskell Setup.lhs install
Installing: /usr/local/bin
Após ter sido feita a instalação de um pacote, o mesmo se torna disponível. Isso pode ser verificado usando a ferramenta ghc-pkg (na linha de comando
$ghc-pkg list). Esse comando lista as bibliotecas disponíveis no ambiente. Essa mesma ferramenta (ghc-pkg) é usada para exibir detalhes de um pacote, desabilitar pacotes, remover pacotes, etc. A ferramenta
cabal instal é a segunda alternativa para instalar pacotes cabal. Com essa ferramenta,que também está disponível como um pacote cabal, é possível instalar pacotes e resolver dependências com uma única ação de linha de comando (particularmente, prefiro a alternativa apresentada anteriormente). Uma restrição é que o pacote precisa estar em um repositório acessível pela ferramenta. Em relação ao exemplo anterior, bastaria executar a linha de comando:
$ cabal install happy
Outros tópicos a serem escritos
- Primeiros passos em Haskell
- (aplicações da linguagem Haskell)
- (sugestão de livros e tutoriais)
- (exemplos simples)
- Definição de tipos de dados
- (lembrar do idioma para instanciar tipos mutualmente recursivos)
- (definição de classes básicas, como Show e Eq => novamente, cuidado com tipos recursivos)
- Discussão sobre Monads
- Como processar arquivos XML em Haskell (lembrar que IO pode resultar em efeitos colaterais)
- GUI (diferentes tecnologias, apresentar exemplos em gtk2hs e glade, ...)
--
RodrigoBonifacio - 02 May 2008