Upload
others
View
0
Download
0
Embed Size (px)
Citation preview
1/86
. . . . . .
Programação Funcional
Aula 7
Entrada e Saída
José Romildo Malaquias
Departamento de ComputaçãoUniversidade Federal de Ouro Preto
2011.2
2/86
. . . . . .
1 Interação com o mundo
2 Operações de entrada e saída em Haskell
3 Programa em Haskell
4 Combinando operações de entrada e saída
5 Outras operações de entrada e saída
6 Saída bufferizada
7 Expressão do
8 readLn e print
9 Números aleatórios
10 Arquivos
3/86
. . . . . .
Layout
1 Interação com o mundo
2 Operações de entrada e saída em Haskell
3 Programa em Haskell
4 Combinando operações de entrada e saída
5 Outras operações de entrada e saída
6 Saída bufferizada
7 Expressão do
8 readLn e print
9 Números aleatórios
10 Arquivos
4/86
. . . . . .
Programas interativos
▶ Programas interativos podem:exibir mensagens para o usuário
obter valores informados pelo usuário
▶ De forma geral um programa irá trocar informações com o restante dosistema computacional:
obter dados do sistema computacional
gravar dados no sistema computacional
▶ Em linguagens imperativas as operações de entrada e saída produzemefeitos colaterais, refletidos na atualização de variáveis globais querepresentam o estado do sistema de computação.
5/86
. . . . . .
Exemplo de programa interativo em C
Programa que obtém dois caracteres digitados pelo usuário e exibi-os emmaiúsculas na tela:#include #include
int main(void){
char x = getchar();char y = getchar();printf(”%c%c\n”, toupper(x), toupper(y));return 0;
}
Supondo que o usuário informe os caracteres ’A’ e ’b’, a execução doprograma produzirá a seguinte interação:
AbAB
6/86
. . . . . .
Exemplo de programa interativo em C (cont.)
▶ A aplicação de função getchar() retorna valores diferentes mesmoquando chamada com os mesmos argumentos (nenhum argumento, nestecaso). A primeira chamada retorna ’A’ e a segunda chamada retorna ’b’.
▶ Isto acontece porque getchar() utiliza uma variável global representandoo dispositivo de entrada padrão. Durante a chamada da função esta variávelé atualizada (efeito colateral), removendo o próximo caracter disponível naentrada e retornando-o como resultado.
▶ Assim, quando a função getchar() é chamada novamente, o próximocaracter a ser consumido é o segundo caracter digitado pelo usuário. Estainformação está na variável global que representa o dispositivo de entradapadrão.
7/86
. . . . . .
Linguagens puras
▶ Em linguagens puras o valor retornado por uma função depende única eexclusivamente dos seus argumentos.
▶ Portanto toda vez que uma função é aplicada em um dado argumento, oresultado é o mesmo.
▶ Assim não é possível implementar uma função que lê um caracter damesma maneira que em linguagens impuras, como C.
▶ Exemplo:let x = getchar ()
y = getchar ()in …
Em uma linguagem pura os valores de x e y serão iguais, uma vez que sãodefinidos aplicando a função getchar ao mesmo argumento.
8/86
. . . . . .
O mundo
▶ Para interagir com o usuário, precisamos de uma representação do sistemade computação onde o programa está sendo executado: o mundo (world).
▶ O mundo é formado por todas as informações no contexto de execução daalicação, incluindo:
dispositivo de entrada padrão (o teclado)
dispositivo de saída padrão (a tela)
sistema de arquivos (arquivos em disco)
conexões de rede
gerador de números pseudo-aleatórios (usa uma semente que depende dosistema, como por exemplo o horário atual)
▶ Para representar o mundo usaremos o tipo abstrato World.▶ Nota: O tipo World não está disponível em Haskell. Ele será usado apenas
para discussão do tema.
9/86
. . . . . .
Modificando o mundo
▶ Em linguagens impuras o mundo (ou parte dele) corresponde a umavariável global atualizável.
▶ Uma função impura que interage com o mundo pode alterar esta variável,de foma que uma aplicação posterior da função ao mesmo argumento poderetornar um valor diferente.
▶ Em uma linguagem pura não há a possibilidade de alterar uma variável.
▶ Uma função pura que interage com o mundo tem um argumento e umresultado adicionais que representam o mundo antes e o mundo depois dainteração.
10/86
. . . . . .
A função primitiva getChar
getChar :: World -> (Char,World)
getChar é uma função primitiva que:
1 recebe um mundo como argumento,
2 obtém o próximo caracter da entrada padrão (um componente do mundo), e
3 resulta em um par formado
pelo caracter obtido da entrada padrão, e
por um novo mundo, idêntico ao anterior exceto na representação da entradapadrão, pois um caracter foi extraído.
11/86
. . . . . .
A função primitiva putChar
putChar :: Char -> World -> World
putChar é uma função primitiva que:
1 recebe um caracter e um mundo como argumentos,
2 exibe o caracter no dispositivo de saída padrão (um componente domundo), e
3 resulta em um novo mundo, idêntico ao anterior exceto na representação dasaída padrão, pois um caracter foi nela inserido.
12/86
. . . . . .
Exemplo usando getChar e putChar
Programa que obtém dois caracteres digitados pelo usuário e exibi-os emmaiúsculas na tela, usando funções puras:
prog :: World -> World
prog world =let (c1,world1) = getChar world
(c2,world2) = getChar world1world3 = putChar (toUpper c1) world2world4 = putChar (toUpper c2) world3
in world4
prog é uma função que:
1 recebe um mundo como argumento,
2 obtém dois caracteres da entrada padrão (um componente do mundo),
3 exibe-os em maiúsculas na saída padrão (outro componente do mundo), e
4 retorna um novo mundo igual ao primeiro exceto pelos dispositivos deentrada e saída: dois caracteres foram extraídos da entrada e doiscaracteres foram inseridos na saída.
13/86
. . . . . .
Execução seqüencial
▶ Observe que o mundo resultante de uma operação é passado comoargumento para a próxima operação.
▶ Isto leva a uma execução sequencial das operações que usam o mundo.
▶ Ao ser executado pelo sistema operacional, o programa recebe o mundo dosistema, realiza as operações especificadas, e devolve o novo mundo parao sistema operacional.
▶ Quando as operações com o mundo são executadas em uma únicaseqüência, a implementação da linguagem pode otimizar o código de formaque o mundo resultante é produzido por uma atualização no mundo dadocomo argumento, ao invés do uso de uma cópia modificada.
14/86
. . . . . .
Exemplo: lendo uma linha
getLine :: World -> (String,World)
getLine world = let (x, world1) = getChar worldin if x == ’\n’
then (””,world1)else let (xs, world2) = getLine world1
in (x:xs, world2)
15/86
. . . . . .
Exemplo: escrevendo uma string
putStr :: String -> World -> World
putStr [] world = worldputStr (x:xs) world = let world1 = putChar x world
world2 = putStr xs world1in world2
16/86
. . . . . .
Exemplo: escrevendo uma string (cont.)
putStrLn :: String -> World -> World
putStrLn xs world = let world1 = putStr xs worldworld2 = putChar ’\n’ world1
in world2
17/86
. . . . . .
Exemplo: soma de dois números
Desenvolver um programa que solicite ao usuário dois números, leia estesnúmeros, e exiba a sua soma.main :: World -> World
main world =let world1 = putStr ”Digite um número: ” world
(str1,world2) = getLine world1world3 = putStr ”Digite outro número: ” world2(str2,world4) = getLine world3world5 = putStrLn (show (read str1 + read str2)) world4
in world5
18/86
. . . . . .
Layout
1 Interação com o mundo
2 Operações de entrada e saída em Haskell
3 Programa em Haskell
4 Combinando operações de entrada e saída
5 Outras operações de entrada e saída
6 Saída bufferizada
7 Expressão do
8 readLn e print
9 Números aleatórios
10 Arquivos
19/86
. . . . . .
O construtor de tipo IO
▶ Em Haskell IO a é o tipo das operações de entrada e saída queinteragem com o mundo e resultam em um valor do tipo a.
▶ IO a é um tipo abstrato, logo sua representação não está disponível nosprogramas em Haskell.
▶ Haskell provê:algumas operações de entrada e saída primitivas, e
um mecanismo para combinar operações de entrada e saída.
20/86
. . . . . .
O construtor de tipo IO (cont.)
▶ Embora o tipo World discutido anteriormente não exista em Haskell,podemos usá-lo para entendermos o funcionamento dos mecanismos deentrada e saída.
▶ IO a poderia ser definido como:
type IO a = World -> (a,World)
ou seja, uma operação de entrada e saída poderia ser uma função querecebe um mundo como argumento e interage com este mundo produzindoum valor e um novo mundo como resultados.
21/86
. . . . . .
A operação getChar
getChar :: IO Char
▶ getChar é uma operação de E/S primitiva que interage com o mundoextraindo o próximo caracter disponível na entrada padrão.
▶ O tipo de getChar poderia ser expresso como:getChar :: World -> (Char,World)
22/86
. . . . . .
A função putChar
putChar :: Char -> IO ()
▶ putChar é uma função primitiva que recebe um caracter e retorna umaoperação de E/S que interage com o mundo inserindo o caracter na saídapadrão.
▶ O tipo de putChar poderia ser expresso como:putChar :: Char -> World -> ((),World)
pois putChar é uma função que recebe um caracter e um mundo comoargumentos, insere o caracter na saída padrão (um componente do mundo),e retorna um par formado pela tupla vazia e pelo novo mundo (igual aomundo inicial exceto pela saída padrão, onde o caracter foi inserido).
▶ Como putChar x apenas insere x na saída padrão e não há nenhumvalor interessante para ser o resultado da operação de E/S, a tupla vazia ()é utilizada como resultado.
23/86
. . . . . .
Layout
1 Interação com o mundo
2 Operações de entrada e saída em Haskell
3 Programa em Haskell
4 Combinando operações de entrada e saída
5 Outras operações de entrada e saída
6 Saída bufferizada
7 Expressão do
8 readLn e print
9 Números aleatórios
10 Arquivos
24/86
. . . . . .
Programa em Haskell
▶ Um programa em Haskell é uma coleção de módulos.
▶ Um dos módulos deve ser chamado Main e deve exportar a variávelmain , do tipo IO t , para algum t.
▶ Quando o programa é executado, a computação main é realizada, e o seuresultado (do tipo t) é descartado.
25/86
. . . . . .
Exemplo de programa em Haskell
module Main (main) where
main :: IO ()main = putChar ’A’
Quando o programa é executado:
1 main recebe (automaticamente) como argumento o mundo existente antesde sua execução,
2 realiza operações de entrada e saída
3 resultando em uma tupla vazia (nenhum valor interessante é produzido), e
4 produzindo um novo mundo que reflete o efeito das operações de entrada esaída realizadas.
26/86
. . . . . .
Preparando e executando um programa em Haskell
1 Grave o código fonte do programa em um arquivo texto, digamosputchar-a.hs
2 Compile o programa (por exemplo usando o Glasgow Haskell Compiler emum terminal):
$ ghc --make putchar-a[1 of 1] Compiling Main ( putchar-a.hs, putchar-a.o )Linking putchar-a ...
3 Execute o programa já compilado:
$ ./putchar-aA
27/86
. . . . . .
Layout
1 Interação com o mundo
2 Operações de entrada e saída em Haskell
3 Programa em Haskell
4 Combinando operações de entrada e saída
5 Outras operações de entrada e saída
6 Saída bufferizada
7 Expressão do
8 readLn e print
9 Números aleatórios
10 Arquivos
28/86
. . . . . .
Sequenciamento de operações
▶ Sendo IO a um tipo abstrato, como poderíamos combinar duasoperações em sequência?
▶ Exemplo: como exibir os caracteres ’A’ e ’B’ em sequência?
▶ Os operadores binários (>>) e (>>=) permitem combinar duasoperações de entrada e saída a serem executadas em sequência.
▶ Estes operadores tem precedência 1 e associatividade à esquerda.
29/86
. . . . . .
Sequenciamento simples
infixl 1 >>(>>) :: IO a -> IO b -> IO b
▶ Recebe duas ações como argumentos, e as executa em sequência.
▶ O resultado da primeira ação é ignorado.
▶ O resultado da segunda ação é o resultado final.
30/86
. . . . . .
Sequenciamento simples (cont.)
▶ Exemplo:Exibir dois caracteres na tela:main = putChar ’A’ >> putChar ’B’
31/86
. . . . . .
Sequenciamento simples (cont.)
▶ Exemplo:Ler um caracter e ignorá-lo, e exibir três outros caracteres:
main = getChar >>putChar ’F’ >>putChar ’i’ >>putChar ’m’
32/86
. . . . . .
Sequenciamento simples (cont.)
▶ (>>) poderia ser definido comop >> q = \world -> let (_, newWorld) = p world
in q newWorld
33/86
. . . . . .
Sequenciamento com passagem de resultado
infixl 1 >>=(>>=) :: IO a -> (a -> IO b) -> IO b
▶ Recebe uma ação e uma função (que resulta em outra ação) comoargumentos.
▶ Executa a primeira ação.
▶ Em seguida aplica a função ao resultado da primeira ação, o que faz comque a segunda ação seja executada.
▶ Desta forma o resultado da primeira ação é passado como argumento paraa função dada.
34/86
. . . . . .
Sequenciamento com passagem de resultado (cont.)
▶ Exemplo:Ler um caracter e exibi-lo na tela:main = getChar >>= (\x -> putChar x)
ou aindamain = getChar >>= \x -> putChar x
ou aindamain = getChar >>= \x ->
putChar x
ou aindamain = getChar >>= putChar
35/86
. . . . . .
Sequenciamento com passagem de resultado (cont.)
▶ Exemplo:Ler um caracter e exibi-lo em maiúsculas na tela:main = getChar >>= (\x -> putChar (toUpper x))
ou aindamain = getChar >>= (putChar . toUpper)
36/86
. . . . . .
Sequenciamento com passagem de resultado (cont.)
▶ Exemplo:Ler um caracter e exibi-lo em minúsculas e em maiúsculas na tela:getChar >>= (\x -> putChar (toLower x) >> putChar (toUpper x))
ou aindagetChar >>= \x -> putChar (toLower x) >> putChar (toUpper x)
ou aindagetChar >>= \x ->putChar (toLower x) >>putChar (toUpper x)
37/86
. . . . . .
Sequenciamento com passagem de resultado (cont.)
▶ (>>=) poderia ser definido comop >>= f = \world -> let (x, newWorld) = p world
in (f x) newWorld
38/86
. . . . . .
Sequenciamento com passagem de resultado (cont.)
▶ (>>=) pode ser usado para definir (>>)p >> q = p >>= \_ -> q
39/86
. . . . . .
Função return
return :: a -> IO a
▶ Às vezes é necessário escrever uma operação de entrada e saída que nãofaz nada com o mundo e retorna um valor especificado.
▶ return recebe um valor e retorna uma operação de entrada e saída quenão faz nada com o mundo e resulta no valor recebido.
▶ Exemplo:acao :: IO Characao = return ’A’
▶ Exemplo:main :: IO ()main = return ’B’ >>= putChar
40/86
. . . . . .
Função return (cont.)
▶ A função return poderia ser definida como:return x = \world -> (x,world)
41/86
. . . . . .
Layout
1 Interação com o mundo
2 Operações de entrada e saída em Haskell
3 Programa em Haskell
4 Combinando operações de entrada e saída
5 Outras operações de entrada e saída
6 Saída bufferizada
7 Expressão do
8 readLn e print
9 Números aleatórios
10 Arquivos
42/86
. . . . . .
A operação getLine
getLine :: IO String
▶ Lê uma linha da entrada padrão.
▶ getLine está na biblioteca padrão.
▶ Possível definição:getLine :: IO StringgetLine = getChar >>= \x ->
if x == ’\n’then ””else getLine >>= \xs -> return (x:xs)
43/86
. . . . . .
A função putStr
putStr :: String -> IO ()
▶ Exibe uma string na saída padrão.
▶ putStr está na biblioteca padrão.
▶ Possível definição:putStr [] = return ()putStr (x:xs) = putChar x >> putStr xs
44/86
. . . . . .
A função putStrLn
putStrLn :: String -> IO ()
▶ Exibe uma string seguida de uma mudança de linha na saída padrão.
▶ putStrLn está na biblioteca padrão.
▶ Possível definição:putStrLn s = putStr s >> putChar ’\n’
45/86
. . . . . .
Exemplo: soma de dois números
soma.hsmodule Main (main) where
main :: IO ()main = putStr ”Digite um número: ” >>
getLine >>= \s1 ->putStr ”Digite outro número: ” >>getLine >>= \s2 ->putStr ”Soma: ” >>putStrLn (show (read s1 + read s2))
Execução do programa onde o usuário informa os números 34 e 17:
3417Digite um número: Digite outro número: Soma: 51
O que aconteceu de errado?
46/86
. . . . . .
Layout
1 Interação com o mundo
2 Operações de entrada e saída em Haskell
3 Programa em Haskell
4 Combinando operações de entrada e saída
5 Outras operações de entrada e saída
6 Saída bufferizada
7 Expressão do
8 readLn e print
9 Números aleatórios
10 Arquivos
47/86
. . . . . .
Saída bufferizada
▶ A saída para o dispositivo padrão de saída é bufferizada: o sistemaoperacional mantém uma área da memória (buffer) onde armazena oscaracteres a serem enviados para o dispositivo de saída.
▶ Geralmente os caracteres enviados para a saída padrão somente sãotransferidos para o dispositivo de saída quando o buffer estiver cheio.
▶ Este mecanismo reduz o número de acesso aos dispositivos de saída (quesão muito mais lentos que o processador), melhorando o desempenho daaplicação.
▶ Por este motivo as mensagens não aparecem imediatamente quando oprograma anterior é executado.
48/86
. . . . . .
Saída bufferizada (cont.)
▶ A função hSetBuffering definida no módulo System.IO da bibliotecapode ser utilizada para configurar o modo de bufferização de umdispositivo.
hSetBuffering :: Handle -> BufferMode -> IO ()
onde Handle é um tipo abstrato que representa um dispositivo de entrada esaída internamente para o Haskell, e BufferMode é o tipo que representaum modo de bufferização:
data BufferMode = NoBuffering| LineBuffering| BlockBuffering (Maybe Int)
49/86
. . . . . .
Saída bufferizada (cont.)
▶ A expressãohSetBuffering hdl mode
é uma ação que configura o modo de bufferização para o handler hdl.
▶ O módulo System.IO define variáveis que representam alguns dispositivospadrões:
stdin :: Handle {- entrada padrão -}stdout :: Handle {- saída padrão -}stderr :: Handle {- saída de erro padrão -}
▶ Então para corrigir o problema no exemplo dado anteriormente devemosadicionar a ação
hSetBuffering stdout NoBuffering
no começo da sequência.
50/86
. . . . . .
Saída bufferizada (cont.)
soma2.hsmodule Main (main) where
import System.IO ( stdout,hSetBuffering, BufferMode(NoBuffering) )
main :: IO ()main = hSetBuffering stdout NoBuffering >>
putStr ”Digite um número: ” >>getLine >>= \s1 ->putStr ”Digite outro número: ” >>getLine >>= \s2 ->putStr ”Soma: ” >>putStrLn (show (read s1 + read s2))
Execução do programa onde o usuário informa os números 34 e 17:
$ ./soma2Digite um número: 34Digite outro número: 17Soma: 51
51/86
. . . . . .
Saída bufferizada (cont.)
Exercício 1
Escreva um programa em Haskell que solicita ao usuário uma temperatura naescala Fahrenheit, lê esta temperatura, converte-a para a escala Celsius, e exibeo resultado. Use os operadores (>>) e (>>=).Use a seguinte equação para a conversão:
C =5
9× (F − 32)
52/86
. . . . . .
Layout
1 Interação com o mundo
2 Operações de entrada e saída em Haskell
3 Programa em Haskell
4 Combinando operações de entrada e saída
5 Outras operações de entrada e saída
6 Saída bufferizada
7 Expressão do
8 readLn e print
9 Números aleatórios
10 Arquivos
53/86
. . . . . .
Expressão do
▶ Tipicamente computações são construídas a partir de longosencadeamentos de (>>) e (>>=).
▶ Haskell oferece a expressão do, que permite combinar várias computaçõesa serem executadas em sequência usando uma notação mais conveniente.
▶ Uma expressão do é uma extensão sintática do Haskell e sempre pode serreescrita como uma expressão normal usando os operadores desequenciamento (>>) e (>>=) e a expressão let.
54/86
. . . . . .
Expressão do (cont.)
▶ Exemplo:Um programa para ler dois números e exibir a sua soma:
module Main (main) where
import System.IO ( stdout,hSetBuffering, BufferMode(NoBuffering) )
main :: IO ()main = do { hSetBuffering stdout NoBuffering;
putStr ”Digite um número: ”;s1
55/86
. . . . . .
Expressão do (cont.)
▶ A expressão do usa layout da mesma maneira que let e where.
▶ Assim as chaves { e } e os pontos-e-vírgula ; podem ser omitidos, sendosubstituídos por uso de indentação adequada.
56/86
. . . . . .
Expressão do (cont.)
▶ Exemplo:Um programa para ler dois números e exibir a sua soma:
module Main (main) where
import System.IO ( stdout,hSetBuffering, BufferMode(NoBuffering) )
main :: IO ()main = do hSetBuffering stdout NoBuffering
putStr ”Digite um número: ”s1
57/86
. . . . . .
Expressão do (cont.)
▶ Tradução da expressão do:do { padrão >= \padrão -> do { ações }
do { x ; ações }≡x >> do { ações }
do { let declarações ; ações }≡let declarações in do { ações }
do { x }≡x
58/86
. . . . . .
Expressão do (cont.)
▶ Exemplo:do putStrLn ”um”
putStrLn ”dois”≡putStrLn ”um” >>putStrLn ”dois”
59/86
. . . . . .
Expressão do (cont.)
▶ Exemplo:do x >= \x ->putStrLn (”Você digitou: ” ++ x)
60/86
. . . . . .
Expressão do (cont.)
▶ Exemplo:do let f xs = xs ++ xs
putStrLn (f ”abc”)≡let f xs = xs ++ xsin putStrLn (f ”abc”)
61/86
. . . . . .
Layout
1 Interação com o mundo
2 Operações de entrada e saída em Haskell
3 Programa em Haskell
4 Combinando operações de entrada e saída
5 Outras operações de entrada e saída
6 Saída bufferizada
7 Expressão do
8 readLn e print
9 Números aleatórios
10 Arquivos
62/86
. . . . . .
A ação readLn
readLn :: Read a => IO a
▶ A ação readLn lê uma linha da entrada padrão e a converte para um tipoque seja instância da classe Read.
▶ Possível definição para readLn:readLn = do str
63/86
. . . . . .
A função print
print :: Show a => a -> IO ()
▶ A função print insere um valor na saída padrão, seguido de uma mudançade linha.
▶ O tipo do valor deve ser instância da classe Show, pois a função show éutilizada para convertê-lo para string.
▶ Print pode ser assim definida:print = putStrLn . show
64/86
. . . . . .
Exemplo: peso ideal
Programa que recebe a altura e o sexo de uma pessoa e calcula e mostra o seupeso ideal, utilizando as fórmulas
sexo peso idealmasculino 72.7× h− 58feminino 62.1× h− 44.7
onde h é a altura.
65/86
. . . . . .
Exemplo: peso ideal (cont.)
pesoideal.hsmodule Main (main) where
import System.IO ( stdout, hSetBuffering, BufferMode(NoBuffering) )
data Sexo = F | M deriving Read
leDado :: Read a => String -> IO aleDado prompt = do putStr prompt
readLn
main :: IO ()main = do hSetBuffering stdout NoBuffering
h 72.7 * h - 58
print pesoIdeal
66/86
. . . . . .
Exemplo: média de 3 notas
Faça um programa que receba três notas de um aluno, calcule e mostre a médiaaritmética das notas e a situação do aluno, dada pela tabela a seguir.
média das notas situaçãomenor que 3 reprovado
entre 3 (inclusive) e 7 exame especial
acima de 7 (inclusive) aprovado
67/86
. . . . . .
Exemplo: média de 3 notas (cont.)
media3notas.hsmodule Main (main) where
import System.IO ( stdout, hSetBuffering, BufferMode(NoBuffering) )
leDado :: Read a => String -> IO aleDado prompt = putStr prompt >> readLn
main :: IO ()main = do hSetBuffering stdout NoBuffering
n1
68/86
. . . . . .
Exemplo: raízes da equação do segundo grau
Faça um programa que leia os coeficientes de uma equação do segundo grau ecalcule e mostre suas raízes reais, caso existam.
69/86
. . . . . .
Exemplo: raízes da equação do segundo grau (cont.)
raizes2grau.hsmodule Main (main) where
import System.IO ( stdout, hSetBuffering, BufferMode(NoBuffering) )
raizes2grau a b c| d > 0 = [ (-b + sqrt d)/(2*a), (-b - sqrt d)/(2*a) ]| d = 0 = [ -b/(2*a) ]| otherwise = [ ]where d = b^2 - 4*a*c
prompt mensagem = putStr mensagem >> readLn
calcRaizes2grau =do putStrLn ”Cálculo das raízes da equação do segundo grau”
putStrLn ”a x^2 + b x + c = 0”a
70/86
. . . . . .
Exemplo: raízes da equação do segundo grau (cont.)
putStrLn (”Raízes: ” ++ show r1 ++ ” e ” ++ show r2)[r] ->putStrLn (”Raíz: ” ++ show r)
[] ->putStrLn ”Não há raízes reais”
main = do hSetBuffering stdout NoBufferingcalcRaizes2grau
71/86
. . . . . .
Layout
1 Interação com o mundo
2 Operações de entrada e saída em Haskell
3 Programa em Haskell
4 Combinando operações de entrada e saída
5 Outras operações de entrada e saída
6 Saída bufferizada
7 Expressão do
8 readLn e print
9 Números aleatórios
10 Arquivos
72/86
. . . . . .
Números aleatórios
▶ Para gerar um número pseudo-aleatório em Haskell podemos usar omódulo System.Random.
▶ Atavés da classe Random é possível obter valores aleatórios de umavariedade de tipos.
▶ A função randomRIO:randomRIO :: Random a => (a, a) -> IO a
Esta função recebe um par de valores (inf, sup) e retorna uma operação deentrada e saída que obtém o próximo valor aleatório do tipo auniformemente distribuído no intervalo [inf, sup].
73/86
. . . . . .
Números aleatórios (cont.)
Exemplo: Lançamento de dois dados:lancadados.hsmodule Main (main) where
import System.IO (hSetBuffering, stdout, BufferMode(NoBuffering))import System.Random (randomRIO)
main :: IO ()main =
do putStrLn ”Lançamento de dois dados”x
74/86
. . . . . .
Números aleatórios (cont.)
Execução do programa:
$ ./lancadadosLancamento de dois dadosFaces obtidas: 3 e 5
$ ./lancadadosLancamento de dois dadosFaces obtidas: 4 e 1
75/86
. . . . . .
Exemplo: adivinhe o número
Escreva um aplicativo que execute adivinhe o número como mostrado a seguir.
▶ Seu programa escolhe o número a ser adivinhado selecionando um inteiroaleatório no intervalo de 1 a 1.000.
▶ O aplicativo exibe o prompt Adivinhe um número entre 1 e 1000.▶ O jogador insere uma primeira suposição.▶ Se o palpite do jogador estiver incorreto, seu programa deve exibir Muito
alto. Tente novamente ou Muito baixo. Tente novamente para ajudar ojogador a zerar mediante uma resposta correta.
▶ O programa deve solicitar ao usuário o próximo palpite.▶ Quando o usuário insere a resposta correta, exiba Parabéns, você adivinhou
o número, e permita que o usuário escolha se quer jogar novamente.
76/86
. . . . . .
Exemplo: adivinhe o número (cont.)
adivinha.hsmodule Main (main) where
import System.IO ( stdout, hSetBuffering, BufferMode(NoBuffering) )import System.Random ( randomRIO )
main :: IO ()main =
do hSetBuffering stdout NoBufferingputStrLn ”Adivinhe o número v1.0”putStrLn ”==========================================”jogar
jogar :: IO ()jogar =
do numero
77/86
. . . . . .
Exemplo: adivinhe o número (cont.)
else return ()
acertar :: Int -> IO ()acertar numero =
do putStrLn ””putStr ”Adivinhe um número entre 1 e 1000: ”s IO BoolsimOuNao prompt =
do putStr prompts return True
78/86
. . . . . .
Exemplo: adivinhe o número (cont.)
| x == ’n’ || x == ’N’ -> return False_ -> simOuNao prompt
79/86
. . . . . .
Layout
1 Interação com o mundo
2 Operações de entrada e saída em Haskell
3 Programa em Haskell
4 Combinando operações de entrada e saída
5 Outras operações de entrada e saída
6 Saída bufferizada
7 Expressão do
8 readLn e print
9 Números aleatórios
10 Arquivos
80/86
. . . . . .
Arquivos
▶ Haskell possui várias definições para lidar com arquivos.
▶ type FilePath = String
Tipo usado para representar o caminho do arquivo, incluindo o seu nome.
▶ readFile :: FilePath -> IO String
Lê o conteúdo de um arquivo como uma única string.
▶ writeFile :: FilePath -> String -> IO ()
Escreve uma string em um arquivo.
▶ appendFile :: FilePath -> String -> IO ()
Acrescenta uma string no final de um arquivo.
81/86
. . . . . .
Exemplo: processar notas em arquivo
Criar um programa para ler de um arquivo os dados dos alunos de uma turma – ocódigo, o nome, a nota na primeira avaliação, a nota na segunda avaliação –calcular a média aritmética das notas e determinar a situação de cada aluno,gravando os resultados em outro arquivo.
82/86
. . . . . .
Exemplo: processar notas em arquivo (cont.)
Arquivo de entrada:
1234 Pedro 1.5 1.71111 Carla 6.2 7.02121 Rafael 8.1 8.84321 Ivan 5.0 5.2
83/86
. . . . . .
Exemplo: processar notas em arquivo (cont.)
module Main (main) where
import System.IO (hSetBuffering, stdout, BufferMode(NoBuffering))
leNotas arquivo =do s
84/86
. . . . . .
Exemplo: processar notas em arquivo (cont.)
writeFile arquivo (unlines (map f resultados))where
f (cod,nom,n1,n2,med,sit) = cod ++ ”\t” ++nom ++ ”\t” ++show n1 ++ ”\t” ++show n2 ++ ”\t” ++show med ++ ”\t” ++sit
main =do hSetBuffering stdout NoBuffering
arq1 > getLinearq2 > getLinenotas
85/86
. . . . . .
Exemplo: processar notas em arquivo (cont.)
Arquivo de saída:
1234 Pedro 1.5 1.7 1.6 reprovado1111 Carla 6.2 7.0 6.6 exame especial2121 Rafael 8.1 8.8 8.45 aprovado4321 Ivan 5.0 5.2 5.1 exame especial
86/86
. . . . . .
Fim
Interação com o mundoOperações de entrada e saída em HaskellPrograma em HaskellCombinando operações de entrada e saídaOutras operações de entrada e saídaSaída bufferizadaExpressão doreadLn e printNúmeros aleatóriosArquivos