Capítulo 2 - Iniciando a programação Haskell em Hugs

Capítulo 2 - Iniciando a programação Haskell em Hugs

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.

2.1 Um primeiro programa em Haskell

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 é:

- ilustrar alguns exemplos com inteiros (Int)

- mostrar o primeiro exemplo de um script

########################################################-}

-- O valor de size é um inteiro (Int), definido como a


-- soma de doze e treze

size :: Int

size = 12+13

 

-- 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 é:

- ilustrar alguns exemplos com inteiros (Int)

- mostrar o primeiro exemplo de um script

########################################################

O valor de size é um inteiro (Int), definido como a


soma de doze e treze

> size :: Int

> size = 12+13

 

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.2. Um exemplo de um literate script

Clique aqui para baixar o código fonte de FirstScript.lhs

A alternativa, o literate considera que qualquer coisa escrita é um comentário do programa, e o Código do programa precisa ser sinalizado explicitamente da mesma forma. Uma versão literate do script está na Figura 2.2, onde ele pode ser visto em uma linha começando com '>', e é separado do resto do texto por linhas em branco. Literate scrips são armazenados em arquivos de extensão '.lhs'.

As duas formas enfatizam diferentes aspectos da programação. A tradicional preferência para o programa, enquanto o literate enfatiza que existe mais programação que simplesmente criar definições. Projetar decisões precisa ser explicado, condições para o uso de funções a assim por diante precis ser escrito e detalhado - isto é benéfico para ambos, o usuário e o programador e de fatopara nós mesmos se formos olhar para um código escrito no passado, e precisarmos modificá-lo e entendê-lo.

2.2 Usando Hugs

Hugs é uma implementação de Haskell que roda em PCs (sob Windows 9x/NT/2000) e sistemas Unix, incluindo Linux e recentemente em Mac (Mac OS X). Ele é livremente distribuído na Home Page do Haskell

http://www.haskell.org/hugs/

Embora disponível em diversas plataformas, os programas apresentam melhor desempenho na plataforma Unix. Vale lembrar que o Hugs é um interpretador. O compilador Haskell mais usado é o ghc. Mas ainda existe muita pesquisa na área para criar um compilador mais eficiente. Hoje a maioria da equipe que criou o Haskell trabalha para a Microsoft e ajudam a desenvolver a .NET.

Iniciando o Hugs

Para iniciar o Hugs o Unix, digite hugs do prompt; para executar Hugs usando um arquivo particular, digite Hugs seguido do nome do arquivo em questão, como em

hugs FirstLiterate

Em sistemas Windows, Hugs é executado a partir do Menu Iniciar no local designado na hora da instalação; para executar Hugs para um arquivo particular, dê um clique duplo no ícone do arquivo em questão.

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.

Winhugs.jpg (18 kbytes)

Figura 2.3. Uma sessão Hugs no Windows

Avaliando expressões em Hugs

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)

-297

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

Comandos hugs começam com dois pontos, ':'. Um resumo dos principais comandos seguem abaixo.

:load arquivo Carrega o arquivo Haskell arquivo.hs ou arquivo.lhs. A extensão .hs ou .lhs não precisa ser incluída no nome do arquivo.
:reload Repete o último comando load.
:edit first.lhs Edita o arquivo first.lhs no editor de textos default. Note que a extensão é necessária nesse caso. Veja a seção seguinte para mais informações sobre edição.
:type exp Retorna o tipo da expressão exp. Por exemplo, o resultado de digitar :type size+2 é Int.
:info name Retorna informações sobre name.
:find name Abre o editor de textos no arquivo contendo a definição de name.
:quit Sai do sistema.
:? Retorna uma lista dos comandos Hugs.
!com Executa o comando Unix ou DOS com.

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.

Editando scripts

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:

  1. Gravar o arquivo atualizado do editor (sem fechá-lo) e
  2. Recarregar o arquivo no Hugs usando :reload arquivo

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.

Uma primeira sessão Hugs

Tarefa 1

Carregue o arquivo FirstLiterate.lhs no Hugs, e avalie os seguintes expressões:


square size
square
double (square 2)
$$
square (double 2)
23 - double (3 - 1)
23 - double 3+1
$$ + 34
13 `div` 5
13 `mod` 5

Com essa base, você pode explicar o que é a função $$?

Tarefa 2

Use o comando Hugs :type para saber o tipo de cada um desses exemplos, incluindo $$.

Tarefa 3

Qual o efeito de se digitar cada uma das expressões abaixo.


double square
2 double

Tente explicar os resultados que você obteve

2.3 A biblioteca Prelude.hs e outras bibliotecas Haskell

Dizemos no Capítulo 1 que o Haskell tem vários tipos embutidos, como integers e listas e funções sobre esses tipos, incluindo funções aritméticas, funções de manipulação de listas, map e ++. Estas definições estão contidas na standard prelude, prelude.hs. Quando Haskell é usado, o default é carregar a biblioteca prelude, como pode ser visto na figura 2.3 a linha:

Reading file: "C:\hugs\lib\Prelude.hs";

que precede o processamento do arquivo FirstLiterate.lhs no qual Hugs foi chamado.

Como Haskell foi desenvolvidoa mais de uma década, o prelude também evoluiu. Começou pequeno, e com o tempo algumas das funções usadas na biblioteca padrão foram movidas para ele, para dar mais liberdade de inclusão de novas funções, quando necessário.

Além das bibliotecas padrão, a distribuição Hugs contribui com várias bibliotecas incluídas que suportam concorrencia, animações funcionais e assim por diante. Outros sistemas Haskell também contribuem com outras bibliotecas, mas todos os sistemas suportam as bibliotecas padrão.

Para trabalhar com as bibliotecas nós precisamos aprender algo sobre módulos em Haskell, que veremos agora.

2.4 Módulos

Uma parte típica de um software de computador contém milhares de linhas código. Para poder gerenciar esse código, precisamos quebrá-lo em pequenos componentes, que chamamos modulos (modules).

Um module tem um nome e contém uma coleção de definições Haskell. Para introduzir um módulo chamado Ant, precisamos começar o programa com a texto:

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:

  1. Existe exatamente um módulo por arquivo
  2. o arquivo Blah.hs ou Blah.lhs contém o módulo Blah

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+4

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` (3*2-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.

Próximo

Home

Anterior