86
1/86 . . . . . . Programação Funcional Aula 7 Entrada e Saída José Romildo Malaquias Departamento de Computação Universidade Federal de Ouro Preto 2011.2

Aula7 EntradaeSaída - DECOM › romildo › 2011-2 › bcc222 › slides › 07-io.pdf · 3/86. . . . . . Layout 1 Interaçãocomomundo 2 OperaçõesdeentradaesaídaemHaskell 3 ProgramaemHaskell

  • Upload
    others

  • View
    1

  • 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