





































Estude fácil! Tem muito documento disponível na Docsity
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
Prepare-se para as provas
Estude fácil! Tem muito documento disponível na Docsity
Prepare-se para as provas com trabalhos de outros alunos como você, aqui na Docsity
Encontra documentos específicos para os exames da tua universidade
Prepare-se com as videoaulas e exercícios resolvidos criados a partir da grade da sua Universidade
Responda perguntas de provas passadas e avalie sua preparação.
Ganhe pontos para baixar
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
arquivo bem detalhado sobre programação em haskell
Tipologia: Notas de estudo
1 / 45
Esta página não é visível na pré-visualização
Não perca as partes importantes!






































A tecnologia dos computadores muda com muita freqüência; os fundamentos, no entanto, permanecem estáticos. A arquitetura de um computador padrão é adaptada de máquinas construídas a meio século. Em programação, idéias modernas como programação orientada a objetos tem décadas de idade para que ter sido adotada no ambiente comercial. Dessa forma, uma linguagem funcional como Haskell é relativamente jovem, mas seu crescimento rápido influencia sua adoção.
Programação funcional oferece uma visão de alto nível da programação, tendo com seus usuários uma variedade de recursos que ajudam a criar elegantes e ainda poderosas bibliotecas gerais de funções.
Um exemplo do poder e generalidade da linguagem, é a função map , a qual é usada para transformar todo elemento da lista de objetos de uma forma específica. Por exemplo, map pode ser usada para dobrar todos os números em uma sequência numérica ou inverter as cores de cada figura de uma lista de imagens.
A elegância da programação funcional é um conseqüência da forma que as funções são definidas: uma equação é usada para dizer qual o valor da função para uma entrada arbitrária. Um exemplo simples é a função addDouble a qual adiciona dois inteiros e dobra sua soma. Ele é definida como:
addDouble x y = 2(x+y)*
onde x e y são as entradas e 2*(x+y) é o resultado.
Haskell começou a ser desenvolvido em 1980 como uma linguagem padrão para programação funcional preguiçosa, e desde então tem sofrido várias atualizações e modificações. Este texto é escrito em Haskell 98, wue consolida o trabalho de Haskell e o qual é suficientemente estável, futuras extensões de resultar no Haskell 2 daqui a alguns anos, mas é esperado implementações que continuem suportando Haskell 98 ainda por um bom tempo.
Nos últimos cinquenta anos os computadores tem evoluído de unidades enormes, caros, raros e lentos para unidades pequenas, baratos, comuns, rápidas e (relativamente) dependentes. Os primeiros computadores eram máquinas ' stand-alone ' (isoladas), mas hoje eles também podem seguir diferentes regras, sendo organizados em rede, ou sendo integrados em máquinas domésticas como carros e máquinas de lavar, da mesma forma como aparecem em computadores pessoais e PDAs.
A despeito disso, os funtamentos dos computadores tem mudado muito pouco nesse período: o propósito de um computador é manipular informações simbólicas. Esta informação pode representar uma situação simples, como a compra de um ítem em um supermercado, ou uma mais complicada, como a previsão de tempo na Europa.
Como essas tarefas são arquivadas? Nós precisamos escrever uma descrição de como a informação é manipulada. Isto é chamado programa e é escrito em uma linguagem de programação. Uma linguagem de programação é uma linguagem formal, artificial usada para dar instruções ao computador. Em outras palavras, a linguagem é usada para escrever o software que controla o comportamento do hardware. Enquanto a estrutura dos computadores tem ficado muito semelhante ao que eram em sua concepção, a forma que eles são programados tem desenvolvido substancialmente. Inicialmente programas são escritos usando instruções que controlavam o hardware diretamente. As linguagens de programação modernas tem trabalhado independente desse problema em outro nível (alto nível), especialmente melhor que as de "baixo nível".
O capítulo 1 introduziu os fundamentos da programação funcional em Haskell. Vamos agora usar o sistema Hugs para alguma programação prática, e o principal propósito deste capítulo é dar uma introdução ao Hugs. Iniciando o programa, vamos aprender os módulos básicos do Haskell, nos quais os programas podem ser escritos em múltipls arquivos interdependentes, e que podem usar as funções "embutidas" nas bibliotecas de prelúdio.
Começaremos o capítulo tomano um primeiro programa Haskell ou script , que consiste de exemplos numéricos do Capítulo 1. Como foi definido, um script pode conter comentários.
{- ###################################### ################
FirstScript.hs
Simon Thompson, Junho 1998
O propósito desse script é:
###################################### ##################-}
-- O valor de size é um inteiro (Int), definido como a
-- a função para o quadrado de um inteiro
square :: Int -> Int
square n = n*n
-- A função para o dobro de um inteiro
double :: Int -> Int
double n = 2*n
-- Um exemplo usando double, square e size
example :: Int
example = double (size - square (2+2))
Figura 2.1. Um exemplo de um script tradicional Clique aqui para baixar o código fonte de FirstScript.hs Um comentário em um script é uma peça chave de informação para uma pessoa que estuda o código. Ele pode conter uma explanação informal aobre como uma função trabalha, como ele pode ou não pode ser usada, assim por diante. Existem dois estilos diferentes de scripts em Haskell, que refletem duas diferentes filosofias de programação. Tradicionalmente, todo código do programa é interpretado com o texto do programa, exceto onde é explicitamente indicado que é comentário. Este é o estilo de FirstScript.hs, na Figura 2.1. Scripts deste estilo são armazenados em arquivos com a extensão '.hs'. Comentários são indicados de duas formas. O símbolo '--' começa um comentário que que ocupará o restante da linha à direita do símbolo. Comentários também podem ser delimitados pelos símbolos '{-' e '-}'. Estes comentários podem ser de tamanho arbitrário, podendo ser de mais de uma linha, bem como englobando outros comentários; então eles são chamados de nested comments.
###################################### ################
FirstScript.hs
Simon Thompson, Junho 1998
O propósito desse script é:
###################################### ##################
O valor de size é um inteiro (Int), definido como a
a função para o quadrado de um inteiro
square :: Int -> Int
square n = n*n
A função para o dobro de um inteiro
double :: Int -> Int
Scripts Haskell trazem a extensão .hs ou .lhs (para literate scripts); somente esses arquivos podem ser carregados, e suas extensões podem ser omitidas quando Hugs é chamado ou pelo comando :load command dentro do Hugs.
Figura 2.3. Uma sessão Hugs no Windows
Como foi dito anteriormente, o interpretador Hugs avalia expressões digitadas no prompt. Entre no Hugs e carregue o programa de uma das formas expostas. Podemos testar no Hugs a avaliação de size, bem como dois exemplos mais complexos:
Main>double 32 - square (size - double 3)
- Main>double 320 - square (size - double 6) 471 Main> Como pode ser visto no exemplo, nós podemos avaliar expressões que usam as definições no script atual. Neste caso, ele é o FirstLiterate.lhs (ou FirstLiterate.hs). Uma das vantagens da interface do Hugs é que é fácil experimentar as funções, tentando avaliações diferentes simplesmente digitando as expressões no teclado. Se quisermos avaliar uma expressão complexa, ela pode ser fácil adiconar ao programa, como na definição
teste :: Int teste = double 320 - square (size - double 6) Feito isso, precisamos apenas digitar test no prompt Main>
Comandos hugs começam com dois pontos, ':'. Um resumo dos principais comandos seguem abaixo.
Todos os comandos ':' podem ser abreviados pela sua letra inicial, como :l arquivo a assim por diante. Detalhes de outros comandos podem ser encontrados na documentação on-line do Hugs que pode ser lida usando um Web browser, como Netscape, Opera, Konqueror ou Internet Explorer.
Hugs pode ser conectado a um editor de textos "default", assim comandos como :edit e :find usam este editor. Isto pode ser determinado pela sua configuração local. O editor de texto default do Unix é o vi ; nos sistemas Windows o Notepad pode ser usado. Detalhes de como o comando :set pode ser usado para alterar o editor default será explicado mais adiante neste tutorial. Usando o comando :edit no Hugs causa uma chamada do editor de textos no arquivo apropriado. Quando o editor é encerrado, o arquivo atualizado é carregado automaticamente. No entanto é mais conveniente deixar o editor executando em uma janela separada e recarregar o arquivo usado:
Dessa forma o editor deixará aberto o arquivo facilitando as modificações. Daremos agora alguns exercícios introdutórios usando Hugs nos primeiros programas de exemplo.
Tarefa 1 Carregue o arquivo FirstLiterate.lhs no Hugs, e avalie os seguintes expressões:
module Ant where
....
Um módulo também pode importar definições de outros módulos. O módulo Bee importará as definições de Ant incluindo uma estrutura import, assim:
module Bee where
import Ant ...
A estrutura import significa que poderemos usar todas as definições de Ant quando criamos definições em Bee. Por esse comportamento dos módulos, nós adotamos as convenções abaixo:
O mecanimo de módulos suporta várias bibliotecas discutidas na seção 2.3, mas podemos também incluir codigo escrito por nós mesmos ou por alguém.
O mecanismo de módulos permite controlar quais definições são importantes e também quais são disponíveis ou exportáveis por um módulo para uso em outros módulos.
Agora estamos em condições de explicar porque o prompt do Hugs aparece como Main>. O prompt mostra o nome do módulo de mais alto nível correntemente carregado no Hugs, e na ausência de um nome para o módulo, ele é chamado de módulo 'Main' (principal).
2.5 Erros e mensagens de erro
Nenhum sistema pode garantir que o que você digita está correto. Hugs não é excessão. Se alguma coisa está errada, em uma mensagem de erro ou em um script, você pode receber uma mensagem de erro. Tente digitar
2+(3+
no prompt do Hugs. Esse é um erro de sintaxe.
A expressão falta parênteses: depois do '4', um fecha parênteses está faltando, para fechar o parêntese aberto antes do '3'. A mensagem de erro diz que o que se seque ao '4' é inexperado:
ERROR - Syntax error in expression (unexpected end of input)
De forma similar, digitando 2+(3+4)) resulta na mensagem
ERROR - Syntax error in input (unexpected `)')
Agora tente digitar a seguinte expressão
double square
Esse é um erro de tipo , uma vez que double é aplicado à função square, sendo que ela pede um integer
ERROR - Type error in application
***** Expression : double square *** Term : square**
***** Type : Int -> Int *** Does not match : Int**
A mensagem indica que alguma coisa do tipo Int era experado, mas alguma coisa do tipo Int -> Int foi apresentada no lugar. Nesse caso, double espera algo do tipo Int como argumento, mas square, do tipo Int -> Int foi encontrado no lugar de um inteiro.
Quando recebemos um erro como o descrito acima, precisamos olhar como o termo , neste caso square do tipo Int -> Int, não confere no contexto no qual é usado: o contexto é dado na segunda linha (double square) e o tipo requerido pelo contexto, Int, é dado na última linha.
Erros de tipo nem sempre nem sempre são mensagens bem estruturadas. Digitando 4 double ou 4 5 receberemos a mensagem
ERROR - Illegal Haskell 98 class constraint in inferred type
***** Expression : fromInt 4 double *** Type : Num ((Int -> Int) -> a) => a**
Será explorado posteriormente detalhes sobre essa mensagem. Por hora é suficiente interpretar esse erro como Erro de tipo.
Tente digitar a expressão
4 div (32-6)*
Não existe divisão por zero. Sendo assim recebemos a mensagem
Program error: {primQrmInteger 4 0}
indicando que a divisão de 4 por zero ocorreu.
Abrangemos até agora a base da programação funcional e mostramos como escrever simples programas em Haskell. Este capítulo cobre os mais importantes tipos básicos do Haskell e também mostra como escrever definições de funções que têm multiplos casos para cobrir situações alternativas. Concluímos olhando alguns detalhes da sintaxe do Haskell. Haskell contém uma variedade de tipos numéricos. Nós já vimos o uso do tipo Int ; veremos agora este e também o tipo Float do ponto- flutuante para números fracionários. Frequentemente em programação nós queremos criar uma opção de valores, se atender ou não uma determinada condição. Algumas condições poderiam ser se um número é maior que outro; ou ainda se dois valores são iguais, e assim por diante. O resultado destes testes - True se a condição for verdadeira e False se for falsa - são chamados de valores Booleanos , depois do século XIX por causa do lógico George Boole, e elas formam o tipo Bool no Haskell. Este capítulo abrange os Booleanos, e como eles são usados para fornecer escolhas em definição de funções por meiode quards. Finalmente, olhamos o tipo caracter - letras individuais, digitos, espaço e assim por diante - que abrange o tipo Char no Haskell. O capítulo provê um material de referência para os tipos básicos; um leitor pode pular o tratamento de Float e precisa detalhar sobre Char , retornando a esse capítulo quando necessário. Cada sessão contém exemplos de funções, e o exercício trata alguns desses. Mais adiante, este capítulo tem os funtamentos dos quais veremos uma variedade de formas de programação podendo planejar e escrever os tópicos deste capítulo.
Os valores booleanos True e False representam o resultado de testes, os quais podem, por instâncias, comparar dois números para igualdade ou verificar se o primeiro é menor que o segundo. O tipo booleano em Haskell é chamado Bool. Os operadores booleanos oferecidos pela linguagem são:
Como Bool contém somente dois valores, nós podemos definir o propósito dos operadores Booleanos por tabelas verdade que mostram o resultado da aplicação do operador a cada possível combinação de argumentos. Para a instância, a terceira linha da primeira tabela diz que o valor de False && True é False e que o valor de False || True é True.
Booleanos podem ser os argumentos ou o resultado das funções. "Ou exclusivo" é a função que retorna True exatamente quando um mas não ambos os argumentos tem o valor True; ela é como o "ou" de um menu de restaurante: você pode escolher um prato, mas não ambos! exOr :: Bool -> Bool -> Bool exOr x y = (x || y) && not (x && y) Podemos ver na figura abaixo uma representação da função, usando retângulos para funções e linhas para valores, como visto no Capítulo
Valores booleanos podem também ser comparados por igualdade e diferença usando os operadore == e /= , onde ambos são do tipo: Bool -> Bool -> Bool Note que /= é a mesma função que exOr, uma vez que ambos retornam o resultado True quando exatamente um dos argumentos é True.
Expressões como True e False, e também numeros como "2", são chamados de literais. Estes são valores literais que não precisam ser avaliados; o resultado da avaliação de um literal é o próprio literal. Podemos usar os literais True e False como argumentos, e nós mesmos definir uma função not: mynot :: Bool -> Bool mynot True = False mynot False = True Podemos também usar uma combinação de literais e variáveis no lado esquerdo da equação para definir exOr: exOr True x = not x exOr False x = x
div 3.mod 3)Note que mod cercado por crases é escrito entre os dois argumentos, esta é a versão infixa da função mod. Qualquer função pode ser escrita da forma infixa.
negate -
Desse ponto em diante, usaremos o termo números naturais para os inteiros não negativos: 0, 1, 2, ...
Existem relações de igualdade e ordenação sobre números inteiros, como existe sobre todos os tipos básicos. Estas funções recebem dois inteiros como entrada e retornam um Bool, que pode ser True ou False. As relações são:
Um exemplo simples usando essas definições é a função que teste se três Ints são iguais. threeEqual :: Int -> Int -> Int -> Bool threeEqual m n p = (m==n) && (n==p)
Dica : se você encontrar dificuldades para responder essa pergunta, tente ver o que a função faz com algumas entradas de exemplo.
fourEqual :: Int -> Int -> Int -> Int -> Bool
div 2)div 2)div 2)div 2) (21 mod 11)3.3 Sobreposição (overloading)
Ambos, inteiros e booleanos, podem ser comparados por igualdades, e alguns símbolos == são usados para ambas operações, embora sejam diferentes. Realmente, == será usado para igualdade sobre qualquer tipo t para os quais é possível definir uma operação de igualdade. Isto significa que (==) tem o tipo Int -> Int -> Bool Bool -> Bool -> Bool
e realmente t -> t -> Bool se o tipo t aceita igualdade
Usando o mesmo símbolo ou nome para operações diferentes é chamado overloading. Um número de símbolos em Haskell são sobrepostos, e veremos mais adiante como sobreposição e manipulação de tipos de sistema em Haskell, e também como usuários podem definir suas próprias sobreposições para nomes ou operadores.