1. 1
LINGUAGEM DE PROGRAMAÇÃO HASKELL
Francisco Daniel Farias Graciano
Francisco Lourenço de Oliveira Neto
Rubens Medeiros Cardoso
Sidney Damasceno Nobre
RESUMO
Este trabalho faz uma demonstração da linguagem de programação Haskell.
Palavras-chave: LIP, Haskell, programação.
2. 2
1. HISTÓRICO
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 grafia e a possibilidade de uma mudança radical na arquitetura de
Von Neumann. 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. Isso consolidaria as linguagens existentes, servindo
como base para pesquisas futuras no desenvolvimento de linguagens. 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.
A primeira versão de Haskell foi definida em 1 de abril de 1990. Seguiuse 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. 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.
A
linguagem
continua
evoluindo,
sendo
as
implementações Hugs e GHC consideradas os padrões de fato. A partir de 2006
começou o processo de definição de um sucessor do padrão 98, conhecido
informalmente por Haskell′ ("Haskell Prime").
2. CARECTERÍSTICAS INOVADORAS
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. 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.
Em questão de características inovadoras em Haskell, segundo a
pesquisa, é relação ao quicksort que é o mais rápido de implementar e mais
direto.
3. 3
2.1 QUICKSORT EM HASKELL
qsort [] = []
qsort (x:xs) = qsort (filter (<x) xs) ++ qsort (filter
(>=x) xs)
2.2 QUICKSORT EM C
void qsort(int a[], int lo, int hi){
{
int h, l, p, t;
if (lo < hi){
l = lo;
h = hi;
p = a[hi];
do{
while ((l < h) && (a[l]<=p))
l = l+1;
while ((h > 1) && (a[h] >= p))
h = h-1;
if (l < h){
t = a[1];
a[1] = a[h];
a[h] = t;
}
} while (l < h);
t = a[l];
a[l] = a[hi];
qsort (a, lo, l-1);
qsort (a, l+1, hi);
}
}
3. TIPOS DE DADOS
TIPO DE
DADO
Bool
Char
DESCRIÇÃO
Enumeração de valores booleanos, que permitem certas
operações lógicas, como conjunção (&&), disjunção (||) e
negação (not).
Enumeração de caracteres 16-bit, Unicode. A faixa dos
primeiros 128 caracteres é idêntica ao ASCII.
CLASSES
EXEMPLO
Read, Show,
Eq, Ord,
Enum,
Bounded
Read, Show,
Eq, Ord,
Enum,
Bounded
True
False
„a‟
4. 4
Double
Float
Int
Integer
Maybe
String
Tuplas
Listas
Ponto flutuante com maior intervalo e precisão que Float.
Ponto flutuante.
Inteiro que cobre, pelo menos, o intervalo de valores [-2^29,
2^29-1].
Inteiro de precisão limitada, com as mesmas funções e
operadores de Int.
Lida com valores opcionais sem terminar o programa e sem
usar o IOError.
Cadeia de caracteres, representada sob forma de lista de Char.
A sintaxe tanto pode ser de lista quanto a abreviação, entre
aspas.
Tipo de dado algébrico de definição de registros heterogêneos,
tuplas. A quantidade máxima de elementos dependa da
implementação, mas a quantidade mínima de quinze elementos
é sempre garantida.
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 de mesmo tipo. Relacionado a concatenação, há o
operador :, que adiciona um elemento no top de uma lista
RealFloat
RealFloat
Integral
6553.612
123
Integral
123
Read, Show,
Eq, Ord
Eq, Ord,
Bounded,
Read, Show
Eq, Ord
“Casa”
[„C‟, „a‟, „s‟,
„a‟]
(„A‟, 11, True)
[1, 2, 3,]
[1...4]
(1:(2:(3:(4:[]))))
4. COMANDOS BÁSICOS
Começamos com o clássico exemplo do programa Hello Word, que pode
ser escrito, em Haskell, do seguinte modo:
module Main where
main = putStrLn "Hello World!"
Como resultado da execução deste programa, é enviada uma mensagem
ao sistema operacional, indicando que o texto passado como argumento para a
função putStrLn deve ser impresso na tela (ou seja, no dispositivo de saída
padrão).
As seguintes funções podem ser usadas para imprimir uma string na tela,
sendo a única diferença entre elas o fato de que a segunda inicia uma nova linha,
depois de imprimir a string:
putStr :: String -> IO ()
putStrLn :: String -> IO ()
O tipo de retorno dessas funções – IO () – indica que é executada uma
ação de E/S e nenhum valor é retornado1. Dizemos que funções como putStr e
putStrLn são funções de E/S ou funções de interação, em contraposição a
funções puras, tais como, por exemplo (++).
Para ler uma linha de caracteres do teclado, podemos usar a função:
5. 5
getLine :: IO(String)
O tipo desta função indica que ela executa uma ação de entrada de dados
e retorna um valor do tipo String.
As ações getLine e putStr podem ser usadas para ler e escrever strings de
caracteres. Para valores de outros tipos, devemos usar as funções readLn e print.
As funções readFile, writeFile e appendFile são implementadas em
termos de funções mais elementares definidas no módulo IO.
5. FUNÇÕES EM HASKELL
Apesar de existirem diversas funções pré-definidas em Haskell, o
interessante da programação funcional é que o usuário defina suas próprias
funções. As funções são definidas através de scripts. Um script é um arquivo que
contém definições de funções associando nomes com valores e tipos.
Ex¹: Função que recebe um inteiro e calcula seu quadrado.
quadrado :: Int -> Int
quadrado x = x * x
A primeira linha de código indica que a função receberá
como argumento um inteiro e retornará um inteiro. A
segunda linha corresponde ao algoritmo para calcular o
quadrado de um número inteiro.
O arquivo deve ser salvo com a extensão “.hs”. Por exemplo,“funcao.hs”.
Depois é só carregar o script no compilador de sua preferência (neste caso
estamos usando o WinHugs) e chamar a função passando um inteiro como
parâmetro.
Ex²:
6. 6
6. IMPLEMENTAÇÃO
Como programa exemplo nada melhor que um programa que calcule a
media de dois números, pois é um exemplo simples de compreender em quase
todas as linguagens de programação.
A função Media no exemplo é uma função que recebe como entrada
números do tipo float que são representados em ponto flutuante.
A função através de seu argumento calcula uma resposta utilizando uma
equação ((nota1 + nota2)/2), onde é dado como entrada dois números: nota1 e
nota2, e a saída é a soma dos dois números divido por dois, ou seja, sua média.
Ex¹:
do {nota1 <- readLn;
nota2 <- readLn
print ((nota1+nota2)/2)}
No exemplo acima, é lido um número do teclado através
de readLn e atribuindo esse número a nota1, da mesma
forma ele faz para ler a nota2. Já no print, a função está
imprimindo na tela o valor de nota1+ nota2 divido por dois,
e por fim finalizando o programa com a chave “}”.
Ex²: Outro exemplo de programa é dado logo abaixo. No
programa seguinte, é dado como entrada vários números inteiros,
devolvendo como saída o total de números que são maiores que
dez.
nsup10 :: [Int] ->Int--Percorrendo toda lista
nsup10[] = 0-- o nsup10 é inicializado com 0, aqui
ele é o nosso contador.
nsup10(x:xs) | x > 10 = 1 +nsup10 xs-- Aqui é feita
a comparação se o numero que entrou é
maior que 10, se caso verdadeiro, então nosso
contador(nsup10), é incrementado em mais um.
|otherwise = nsup10 xs-- mostra na tela o nsup10
xs, ou seja o final do programa, onde mostra o
nosso contador
7. 7
7. DIFICULDADES
A disponibilidade de material para Haskell é grande, nesse trabalho
especificamente foram usados dois livros:
Real World Haskell
Haskell - Uma Abordagem
Prática
Sobre dificuldade no momento da instalação, não houve complicações,
são vários os compiladores com suporte a linguagem Haskell como: GHC,
WinHugs, nhc98, HBC, Helium. Para esse trabalho foi usado como exemplo o
WinHugs:
7.1 INSTALANDO O WINHUGS
Passo 1: