Haskell (linguagem de programação)






























































































































































































































































































































































































































































































































































































































































































































































































































































































































































Haskell

Logo do Haskell

Paradigma

funcional, não rígida, modular
Surgido em

1990
Criado por

Simon Peyton-Jones, Paul Hudak,[1]Erik Meijer, Philip Wadler, Lennart Augustsson, Dave Barton, Brian Boutel, Warren Burton, Joseph Fasel, Kevin Hammond, Ralf Hinze, John Hughes, Thomas Johnsson, Mark Jones, John Launchbury, John Peterson, Alastair Reid, Colin Runciman, Philip Wadler.

Estilo de tipagem:
forte, estática, inferida

Compiladores

GHC, Hugs, nhc
Dialetos:

Helium, O'Haskell, Template Haskell, PolyP
Influenciada por

Miranda, ML
Influenciou

C#, Cat, Clojure, F#, Python, Scala

Extensão do arquivo:
.hs, .lhs

Haskell é uma linguagem de programação puramente funcional, de propósito geral, nomeada em homenagem ao lógico Haskell Curry. Como uma linguagem funcional, a estrutura de controle primária é a função; a linguagem é baseada nas observações de Haskell Curry [2][3] e seus descendentes intelectuais.[4][5] Seu último padrão semi-oficial é o Haskell 98, destinado a especificar uma versão mínima e portável da linguagem para o ensino e como base para futuras extensões.


Haskell é a linguagem funcional sobre a qual mais se realizam pesquisas atualmente. Muito utilizada no meio acadêmico. É uma linguagem nova, elaborada em 1987, derivada de outras linguagens funcionais como por exemplo Miranda e ML. Ela se baseia em um estilo de programação em que se enfatiza mais o que deve ser feito (what) em detrimento de como deve ser feito (how). É uma linguagem que possui foco no alcance de soluções para problemas matemáticos, clareza, e de fácil manutenção nos códigos, e possui uma variedade de aplicações e apesar de simples é muito poderosa.




Índice






  • 1 História


  • 2 Características


    • 2.1 Sintaxe


    • 2.2 Listas


    • 2.3 Tipos de dado


    • 2.4 Operadores




  • 3 Paradigma


    • 3.1 Visão critica do paradigma funcional


      • 3.1.1 Vantagens


      • 3.1.2 Desvantagens






  • 4 Aplicações


  • 5 Exemplos


  • 6 Implementações


  • 7 Leitura adicional


  • 8 Referências


  • 9 Referências bibliográficas


  • 10 Ver também


  • 11 Ligações externas





História |


O conceito de avaliação preguiçosa já estava difundido no meio acadêmico desde o final da década de 1970. Esforços nessa área incluíam técnicas de redução de grafo e a possibilidade de uma mudança radical na arquitetura de von Neumann.[6] Após o lançamento de Miranda em 1985, diversas outras linguagens funcionais de semântica não rígida proliferaram, como Lazy ML, Orwell, Alfl, Id, Clean, Ponder e Daisy (um dialeto de Lisp). Mesmo após dois anos, Miranda ainda era a mais usada, mas não estava em domínio público.


Em setembro 1987 foi realizada uma conferência Functional Programming Languages and Computer Architecture (FPCA '87), em Oregon, o consenso foi a criação de um comitê com o objetivo de construir um padrão aberto para tais linguagens.[7] Isso consolidaria as linguagens existentes, servindo como base para pesquisas futuras no desenvolvimento de linguagens.[8] A primeira reunião do comitê foi realizada em janeiro de 1988, e algumas das metas da linguagem foram discutidas. A linguagem deveria ser de fácil ensino, deveria ser completamente descrita através de uma sintaxe e semântica formal, deveria estar disponível livremente. Haskell foi criada da necessidade de unir as outras linguagens do mesmo paradigma em uma só.


Os objetivos principais deste comitê, ao projetar essa nova linguagem, deveria seguir algumas especificações:


  • Ser viável para o ensino, pesquisa e aplicações, incluindo sistema de larga escala;

  • Ser completamente descritiva via publicação no tocante à sua sintaxe e sua semântica;

  • Não ser proprietária, tal que qualquer um pudesse implementá-la e distribuí-la;

  • Basear-se em ideias que envolvessem o senso comum;

  • Deveria reduzir a diversidade desnecessária de outras linguagens funcionais.

A primeira versão de Haskell foi definida em 1 de abril de 1990.[9] Seguiu-se a versão 1.1 em agosto de ano seguinte, a versão 1.2 em março de 1992, a versão 1.3 em maio de 1996 e a versão 1.4 em abril de 1997.[10] Esforços posteriores culminaram no Haskell 98, publicado em janeiro de 1999 e que especifica uma versão mínima, estável e portável da linguagem e a biblioteca para ensino. Esse padrão sofreu uma revisão em janeiro de 2003.[11]


A linguagem continua evoluindo, sendo as implementações Hugs e GHC consideradas os padrões de facto. A partir de 2006 começou o processo de definição de um sucessor do padrão 98, conhecido informalmente por Haskell′ ("Haskell Prime").[12]



Características |


Características do Haskell incluem o suporte a funções recursivas e tipos de dados, casamento de padrões, list comprehensions, guard statements e avaliação preguiçosa, esta, um elo em comum entre os diversos grupos de desenvolvimento da linguagem.[13] A combinação destas características pode fazer com que a construção de funções que seriam complexas em uma linguagem procedimental de programação tornem-se uma tarefa quase trivial em Haskell. Segundo dados de 2002, é a linguagem funcional sobre a qual mais pesquisa está sendo realizada. Muitas variantes tem sido desenvolvidas: versões paralelizáveis do MIT e Glasgow, ambas chamadas Parallel Haskell, outras versões paralelas e distribuídas chamadas Distributed Haskell (anteriormente Goffin) e Eden, uma versão chamada Eager Haskell e várias versões orientadas a objetos: Haskell++, O'Haskell e Mondrian.


Uma versão educacional do Haskell chamada Gofer foi desenvolvida por Mark Jones. Ela é oferecida pelo HUGS.
Existe também uma versão do Haskell que permite orientação a aspectos (POA), chamada AspectH.


A linguagem de programação Haskell é fundamentada em Lambda Cálculo, que serve como base no desenvolvimento do artigo e apresenta um único tipo, as funções. Haskell apresenta um tipagem forte e estática, onde as expressões são ligadas a um mesmo tipo em tempo de compilação; e apresenta o polimorfismo universal, possui um tipo genérico e a mesma definição é usada para vários tipos.



Sintaxe |


Em Haskell existem apenas funções, e todas as funções são unárias. O que, em outras linguagens de programação seriam funções binárias, ternárias, etc, em Haskell são funções cujo valor de retorno são outras funções - o que se chama currying, termo derivado de Haskell Curry.


Uma função que, dados dois números, retorna sua soma poderia ser declarada como:


soma x y =x+y

O que parece ser uma função binária é, logicamente, uma função unária (soma, cuja entrada é x) que retorna outra função. Em outras palavras, soma x é a função unária que, dado y retorna x + y, e soma é a função unária que, dado x, retorna x +.


Em Haskell não existem variáveis globais, apenas funções e variáveis locais, definidas dentro do escopo de cada função.


Também não há estruturas de loop, ou instruções do tipo goto.


O if é implementado através de |, que significa a restrição do domínio do argumento da função.


O exemplo abaixo mostra uma implementação do fatorial que usa a recursividade e o if:


fat 0 = 1
fat n | n > 0 = n*fat(n-1)

Em palavras: a primeira linha diz que o fatorial de zero é um; a segunda linha diz que o fatorial de um número n qualquer, desde que n seja maior que zero, pode ser calculado a partir do fatorial de (n-1). Esta implementação não é eficiente, mas serve como exemplo didático.



Listas |


Há duas funcionalidades importantes para a construção de listas. A primeira é a list comprehension, que permite construir listas sob forma de conjuntos. Por exemplo, o código [ x | x <- [0..], x^2>3 ] cria uma lista de elementos x a partir do gerador <- [0..] (o conjunto dos números naturais), que atendam o predicado x^2>3 (o símbolo <- representa o pertence, {displaystyle in ,}in,, da teoria dos conjuntos). Pode-se combinar geradores numa mesma list comprehension.


A segunda funcionalidade é a sequência aritmética, que permite construir listas sob forma de intervalos. Por exemplo, o código [2..10] cria uma lista de inteiros de 2 a 10. Pode-se omitir o fim do intervalo; [2..] gera uma lista infinita de inteiros a partir de 2.


Há três funções primordiais sobre listas em Haskell, das quais outras funções podem ser combinadas.[14] A primeira é foldl, que adiciona um operador dado entre cada elemento da lista, retornando o resultado da expressão gerada. Para concatenar uma lista de cadeias de caracteres cadeia = ["Uma", " ", "cadeia"] pode-se usar foldr1 (++) cadeia. A segunda é map, que executa uma função a todos os elementos da lista, retornando uma nova lista. A terceira é filter, que filtra a lista a partir de um predicado.



Tipos de dado |


A tipagem de Haskell é forte. Cada expressão possui um tipo, e é possível obtê-lo em tempo de compilação através de inferência de tipo. Os tipos básicos da linguagem incluem:





























































































Tipo de dado Descrição Classes Exemplo da sintaxe
Bool
Enumeração de valores booleanos, que permitem certas operações lógicas, como conjunção (&&), disjunção (||) e negação (not).
Read, Show, Eq, Ord, Enum, Bounded
True
False
Char Enumeração de caracteres 16-bit, Unicode. A faixa dos primeiro 128 caracteres é idêntica ao ASCII. Read, Show, Eq, Ord, Enum, and Bounded
'a'
Double
Ponto flutuante com maior intervalo e precisão que Float
RealFloat
Either Eq, Ord, Read, Show
Float Ponto flutuante RealFloat
6553.612
321.6e-3
IO Tipo abstrato para operações de E/S, como putStr, print, getChar, getLine e readIO. Monad, Functor
IOError Tipo abstrato para erros nas operações de E/S com IO. Show, Eq
Int
Inteiro que cobre, pelo menos, o intervalo de valores [-2^29, 2^29 - 1].
Integral
123
Integer
Inteiro de precisão ilimitada, com as mesmas funções e operadores de Int
Integral
123
Maybe Lida com valores opcionais ou ilegais sem terminar o programa e sem usar o IOError de IO. Eq, Ord, Read, Show
Ordering Eq, Ord, Bounded, Enum, Read, Show
String
Cadeia de caracteres, representada sob forma de lista de Char. A sintaxe tanto pode ser de lista quanto a abreviação, entre aspas.

"Texto"
['T','e','x','t','o']
Tuplas Tipo de dado algébrico de definição de registros heterogêneos, tuplas. A quantidade máxima de elementos depende da implementação, mas a quantidade mínima de quinze elementos é sempre garantida.[15]
Eq, Ord, Bounded, Read, Show
('A',11,True)
Listas Tipo de dado algébrico de definição de registros homogêneos listas. Entre os operadores disponíveis encontra-se !!, que retorna o n-ésimo elemento da lista, e ++, que concatena duas listas distintas de mesmo tipo. Relacionado a concatenação, há o operador :, que adiciona um elemento no topo de uma lista. Eq, Ord
[1,2,3,4]
[1..4]
(1:(2:(3:(4:))))

A linguagem ainda define diversas classes padrão:
























































































Tipo de dado Descrição Prove
Bounded Delimita um tipo de dado
Enum Prove operações em tipo sequencialmente ordenados.
succ, pred, toEnum, enumFrom
Eq Prove operadores de igualdade.
==, /=
Floating
Fractional
Functor Usado por tipos que podem ser mapeados.
Integral
Ord Prove operadores de ordenação.
, <, >=, >
Monad Prove operações sobre mônadas.
MonadPlus
Num
Read
Real
RealFloat
RealFrac
Show


Operadores |


Além dos operadores específicos de certos tipos de dado supracitados, vale notar também alguns outros. O operador . realiza a composição de funções. Por exemplo, a expressão ((2+).(3*).(4-)) 2 retorna 8, e significa ((4−2)∗3)+2{displaystyle ((4-2)*3)+2}((4-2)*3)+2.


A potenciação pode ser feita através do operador **. Entretanto estão disponíveis também duas versões mais eficientes. Para ^^, o expoente deve ser um inteiro; para ^, o expoente deve ser um inteiro não negativo.



Paradigma |


Paradigma funcional enfatiza o processo de identificar blocos e partes repetidas de código e constroem funções que encapsulam a funcionalidade dentro de uma simples definição. Isto aumenta a confiabilidade (não ocorrem erros de tipagem). Um programa desenvolvido nesse paradigma é, por si só, uma função, que toma como entrada os argumentos passados pelo usuário, e lhe retorna alguma saída (resultado), possivelmente utilizando-se de outras funções. O paradigma de programação funcional enxerga todos os subprogramas como funções que recebem argumentos e retornam soluções simples. A solução retornada é baseada inteiramente na entrada e o tempo em que uma função é chamada é irrelevante sendo possível a passagem de uma função como parâmetro. O programa passa a ser uma lista de funções, sendo o próprio programa principal uma lista.



Visão critica do paradigma funcional |



Vantagens |



  • Construção eficiente de programas: a construção rápida de programas impulsiona o caráter da aprendizagem e da prototipação de programas complexos.

  • Um alto nível de abstração, especialmente quando as funções são utilizadas, suprimindo muitos detalhes da programação e minimizando a probabilidade da ocorrência de muitas classes de erros

  • A não dependência das operações de atribuição permite aos programas avaliações nas mais diferentes ordens. Esta característica de avaliação independente da ordem torna as linguagens funcionais as mais indicadas para a programação de computadores maciçamente paralelos.

  • A ausência de operações de atribuição torna os programas funcionais muito mais simples para provas e análises matemáticas do que os programas procedurais.



Desvantagens |



  • Problemas que envolvam muitas variáveis (ex. banco de dados) ou muitas atividades sequenciais, essas são muitas vezes mais fáceis de se trabalhar com programas procedurais ou programas orientados a objeto.

  • Implementações ineficientes: considerando que as funções têm um caráter recursivo em suas definições, invariavelmente estas tendem a ser mais ineficientes computacionalmente que as linguagens imperativas, pois tem maior chance de ocorrer erros e possuem um grande uso de memória.



Aplicações |


Os pontos fortes da linguagem Haskell têm sido bem aplicados em alguns projetos. É cada vez mais utilizada em aplicações comerciais.[16] O compilador e interpretador Pugs criado por Audrey Tang é uma versão completa da linguagem Perl 6. Darcs é um sistema de controle de versões baseado em mudanças (change-based) com várias características inovadoras. A Linspire GNU / Linux escolheu Haskell para desenvolvimento das ferramentas do sistema .[17]Xmonad é um gerenciador de janelas "tile-based" para o X Window System escrito inteiramente em Haskell. Bluespec SystemVerilog é uma linguagem feita como uma extensão do Haskell.



Exemplos |


O difundido caso do Programa Olá Mundo pode ser exemplificado em Haskell da seguinte forma:


olamundo :: IO()
olamundo = putStrLn "Olá, Mundo!"

A clássica definição da função fatorial:


fatorial :: Integer -> Integer
fatorial 0 = 1
fatorial n | n > 0 = n * fatorial (n-1)

Ou em uma linha:


fatorial n = if n > 0 then n * fatorial (n-1) else 1

Este artigo descreve o fatorial como uma função recursiva, terminando com um caso que serve como base. É semelhante ao encontrado nas descrições de fatoriais em livros didáticos de matemática. Grande parte do código Haskell é semelhante ao padrão da notação matemática na potencialidade expressiva e na sintaxe.
A primeira linha da função fatorial descreve os tipos desta função; embora seja opcional, é considerado bom estilo [18] incluí-la. Ela pode ser lida como a função fatorial (fatorial) tem tipo (::) inteiro para inteiro (Integer -> Integer). Ou seja, ele tem um inteiro como um argumento e retorna outro inteiro. O tipo de uma definição é inferido automaticamente se o programador não forneceu uma notação de tipo.


A segunda linha depende de um casamento de padrões (pattern matching), uma característica importante do Haskell. Note que os parâmetros da função são separados por parênteses e não por espaços. Quando o argumento da função é 0 (zero) será devolvido o inteiro 1 (um). Para todos os outros casos, a terceira linha é tentada. Esta é a recursividade, e executa a função novamente até que um caso que sirva como base seja atingido.


Um "guard" protege a terceira linha de números negativos, sendo que um fatorial não permite números negativos, indefinido-o. Sem um "guard" essa função seria recursiva "fatorando" todos os números negativos, sem nunca chegar à base 0. Se um inteiro negativo é passado para o fatorial funcionar como um argumento, o programa irá falhar com um erro "runtime". De último caso, poderia ser tratada esta condição de erro e imprimir uma mensagem de erro adequada em seu lugar.


A descrição acima é parecida com as descrições matemática, tais como definições de uma função f=g∘h{displaystyle f=gcirc h}f = g circ h e não como uma atribuição de um valor numérico para uma variável.


Uma outra definição da função fatorial (usando uma notação de lista em Haskell e a função padrão product):


fatorial n = product [1..n]

A mesma função mas agora no estilo point-free. Repare-se que os argumentos desaparecem (o ponto significa composição de funções):


fatorial = product . enumFromTo 1

Uma implementação da função que retorna o n-ésimo termo na seqüência de Fibonacci:


fib 0 = 0
fib 1 = 1
fib n = fib (n - 2) + fib (n - 1)

Uma função que retorna uma lista dos números de Fibonacci:


fibs@(_:rest) = 0 : 1 : (zipWith (+) fibs rest)

A função anterior cria uma lista infinita, que é possível graças a avaliação preguiçosa.
Poderia-se implementar fib como:


fib n = fibs !! n

O algoritmo quicksort pode ser elegantemente escrito em Haskell:


qsort     = 
qsort (h:t) = qsort menores_que_h ++ [h] ++ qsort maiores_que_h
where
menores_que_h = [x | x <- t, x < h]
maiores_que_h = [x | x <- t, x >= h]

Uma forma mais compacta desse mesmo algoritmo seria:


quicksort  = 
quicksort (s:xs) = quicksort [x|x <- xs,x < s] ++ [s] ++ quicksort [x|x <- xs,x >= s]

Nota: Por causa das excessivas cópias e concatenações de listas, este código pode ser lento.


Implementações |


As seguintes implementações estão totalmente, ou quase, de acordo com o padrão Haskell 98. Todas são distribuídas sob licenças código aberto.




  • GHC. O Glasgow Haskell Compiler gera código nativo de diferentes arquitecturas e pode também gerar código C. Ele é provavelmente o mais popular compilador Haskell, e algumas bibliotecas (como bindings para OpenGL) funcionam apenas com ele.


  • Hugs é um interpretador de bytecode. Oferece rápida compilação dos programas e razoável velocidade de execução. Também dispõe de uma simples biblioteca gráfica. Hugs é ideal para pessoas que estão aprendendo os básicos de Haskell. É a mais portável e leve das implementações de Haskell.

  • nhc98[19] é outro compilador que gera bytecode. O bytecode resultante executa significativamente mais rápido do que o equivalente do Hugs. Nhc98 foca na minimização do uso de memória, e é uma boa escolha para máquinas velhas/lentas.

  • HBC é outro compilador Haskell para código nativo. Seu desenvolvimento não está ativo, mas ele é funcional.

  • Helium[20] é um novo dialeto do Haskell. O foco é na facilidade de aprendizado. Atualmente carece de typeclasses, tornando-o incompatível com muitos programas Haskell.



Leitura adicional |



  • Página do livro: Haskell: Uma Abordagem Prática, um livro de nível introdutório a médio sobre a linguagem Haskell, com uma apresentação crescente as principais características da linguagem.


Referências




  1. Sítio de Paul Hudak


  2. Curry, Haskell (1934), «Functionality in Combinatory Logic», Proceedings of the National Academy of Sciences, 20, pp. 584–590 


  3. Curry, Haskell B.; Feys, Robert (1958), Combinatory Logic Vol. I, Amsterdam: North-Holland  Parâmetro desconhecido |other1-first= ignorado (ajuda); Parâmetro desconhecido |other1-last= ignorado (ajuda), with 2 sections by William Craig, see paragraph 9E


  4. De Bruijn, Nicolaas (1968), Automath, a language for mathematics, Department of Mathematics, Eindhoven University of Technology, TH-report 68-WSK-05. Reprinted in revised form, with two pages commentary, in: Automation and Reasoning, vol 2, Classical papers on computational logic 1967-1970, Springer Verlag, 1983, pp. 159-200.


  5. Howard, William A. (1980) [original paper manuscript from 1969], «The formulae-as-types notion of construction», in: Seldin, Jonathan P.; Hindley, J. Roger, To H.B. Curry: Essays on Combinatory Logic, Lambda Calculus and Formalism, ISBN 978-0-12-349050-6, Boston, MA: Academic Press, pp. 479–490 .


  6. Hudak 2007, p. 2


  7. Hudak 2007, p. 3


  8. «Preface». Haskell 98 Language and Libraries: The Revised Report (em inglês). Sítio oficial. Dezembro de 2002. Consultado em 29 de setembro de 2008 


  9. «The History of Haskell» (em inglês). Sítio oficial. Consultado em 29 de setembro de 2008 


  10. Hudak 2007, p. 5


  11. Simon Peyton Jones (dezembro de 2002). «Haskell 98 Language and Libraries: The Revised Report» (em inglês). Sítio oficial. Consultado em 29 de setembro de 2008 


  12. «Future development of Haskell» (em inglês). Sítio oficial. Consultado em 29 de setembro de 2008 


  13. Hudak 2007, p. 8


  14. Du Bois


  15. The Haskell 98 Report, s. 6.1.4


  16. «Haskell in Industry» 


  17. «Linspire/Freespire Core OS Team and Haskell». Debian Haskell mailing list. 2006 


  18. HaskellWiki: Type signatures as good style


  19. «nhc98». www.cs.york.ac.uk. Consultado em 1 de maio de 2011 


  20. «WebHome < Helium < TWiki». www.cs.uu.nl. Consultado em 1 de maio de 2011 



Referências bibliográficas |





  • Naomi Hamilton (19 de setembro de 2008). «The A-Z of Programming Languages: Haskell» (em inglês). Computerworld. Consultado em 29 de setembro de 2008 


  • Paul Hudak, John Hughes, Simon Peyton Jones, Philip Wadler (16 de abril de 2007). «A History of Haskell: Being Lazy With Class» (PDF) (em inglês). Third ACM SIGPLAN History of Programming Languages Conference (HOPL-III). Consultado em 29 de setembro de 2008  !CS1 manut: Nomes múltiplos: lista de autores (link)


  • André Rauber Du Bois. «Programação Funcional com a Linguagem Haskell» (PDF) (em inglês). Universidade de Heriot-Watt. Consultado em 30 de setembro de 2008 


  • «The Haskell 98 Report: Predefined Types and Classes» (em inglês). Sítio oficial. Dezembro de 2002. Consultado em 30 de setembro de 2008 




Ver também |








Outros projetos Wikimedia também contêm material sobre este tema:

Wikilivros

Livros e manuais no Wikilivros


  • Wikilivros


  • Programação funcional


Ligações externas |




  • Sítio oficial (em inglês)


  • Introdução ao Haskell 98 (em inglês)


  • Outros exemplos de códigos em Haskell (em inglês)


  • Tutorial, em http://www.lisperati.com/haskell/ (em inglês)



















Popular posts from this blog

flock() on closed filehandle LOCK_FILE at /usr/bin/apt-mirror

Mangá

Eduardo VII do Reino Unido