Baixe o app para aproveitar ainda mais
Prévia do material em texto
Programação Funcional (COMP0393) Leila M. A. Silva 1 Entrada e Saída (COMP0393) Aula 22 2 3 Introdução Sistemas computacionais interagem com o “mundo” Interações podem requerer Sequencialidade Percepção de mudanças no “mundo” Causam problemas com o modelo de Programação Funcional porque Programas funcionais não expressam ordem de avaliação e, ainda menos, sequencialidade Com avaliação preguiçosa, a ordem não é fácil predizer somente olhando no texto do programa Não existem efeitos colaterais inputInt :: Int inputDiff = inputInt - inputInt 4 I/O com PF pura Um novo tipo de valores – chamados ações IO a Uma ação realiza um efeito colateral e devolve um valor Ações acontecem “fora do mundo funcional” Para uma função, uma ação é um valor constante Funções não “executam” ações mas somente criam ações compostas a partir de ações mais simples Ações interagem “com o mundo funcional” O valor devolvido pela execução de uma ação pode ser “capturado” e passado para uma função É como se tivéssemos uma linguagem acima de Haskell 5 Exemplos de ações Algumas ações pré-definidas getLine :: IO String getChar :: IO Char Funções “construtoras” de ações putStr :: String → IO () Assim, por exemplo, putStr "Oi pessoal" é uma ação. putStrLn :: String → IO () putStrLn = putStr . (++ "\n" ) Compondo funções construtoras de ações, posso definir outras print :: Show a => a → IO () print = putStrLn . show print imprime valores de vários tipos 5 putStr e putStrln podem ser consideradas como construtoras de ações 6 Compondo ações com a notação do A notação do permite “construir” sequências de ações capturar um valor retornado por uma ação o valor capturado é passado para as próximas ações echo :: IO () echo = do str ← getLine putStr str Duas ações O valor produzido pela primeira ação é capturado em str e passado para a seguinte 7 Observe que do junta uma sequência de ações para formar uma nova ação do permite captura Só é possível capturar e utilizar o resultado de uma ação dentro de um do O tipo da ação composta do ... é dado pelo tipo da “última ação” 7 Por enquanto, do é a única construção que permite compor ações 8 Exemplos put3times :: String → IO () put3times str = do putStrLn str putStrLn str putStrLn str putNtimes :: Int → String → IO () putNtimes n str = if (n<=1) then putStrLn str else do putStrLn str putNtimes (n-1) str put3times = putNtimes 3 8 Note a semelhança com programas imperativos 9 read2lines :: IO () read2lines = do getLine getLine putStr “Duas linhas lidas." Lê linhas sem capturá-las Exemplos 10 getInt :: IO Int getInt = do line ← getLine return (read line :: Int) A ação return add2Ints :: IO () add2Ints = do n1 ← getInt n2 ← getInt putStrLn (show (n1+n2)) Permite construir uma ação que simplesmente retorna um valor 10 return 3, é uma ação que simplesmente retorna (sem realizar nenhum efeito colateral) o valor 3 11 Definições locais dentro de um do add2Ints :: IO () add2Ints = do n1 ← getInt n2 ← getInt let summ = n1+n2 putStrLn (show summ) add2Ints :: IO () add2Ints = do n1 ← getInt n2 ← getInt let summ = n1+n2 in putStrLn (show summ) 12 copy :: IO () copy = do str ← getLine putStrLn str copy Note a recursão A captura é feita pelo “str ←” “str ←” lembra uma atribuição ... porém: str não é variável imperativa cria-se uma nova variável (“atribuição” only once) Para interromper usa Ctrl-C senão roda indefinidamente Iteração (Loops) 13 copyN :: Integer -> IO () copyN n = if n<=0 then return () else do str ← getLine putStrLn str copyN (n-1) Podemos controlar o número de vezes a executar fazendo: Iteração (Loops) 14 copyEmpty :: IO () copyEmpty= do str ← getLine if str == “” then return () else do putStrLn str copyEmpty Podemos controlar a terminação do laço com uma condição nos dados; copiar até uma linha vazia ser encontrada: Iteração (Loops) 15 copyCount :: Integer -> IO () copyCount n = do str ← getLine if str == “” then putStrLn (show n ++ “ linhas copiadas.”) else do putStrLn str copyCount (n+1) Podemos contar o número de linhas copiadas até encontrar uma linha vazia: Iteração (Loops) A função deve ser chamada com copyCount 0 16 Iteração e recursão while :: IO Bool → IO () → IO () while test action = do res ← test if res then do action while test action else return () Repetição de uma ação IO enquanto uma condição for verdadeira. 17 Exemplo Copia entrada na saída copyInpOut :: IO () copyInpOut = while notEOF (do line ← getLine putStrLn line ) A ação isEOF :: IO Bool é predefinida no módulo System.IO. Testa o final de uma entrada de dados. Note que notEOF é também uma ação. notEOF :: IO Bool notEOF = do cond ← isEOF return (not cond) 17 cat unix Mais exemplos Ler n inteiros e retornar a soma deles -- A soma é acumulada no segundo argumento, res. A ação getInt está definida no slide 10. somaInts :: Int -> Int -> IO Int somaInts n res = if n <=0 then return res else do m <- getInt somaInts2 (n-1) (res+m) main :: IO () main = do n <- getInt val <- somaInts n 0 putStr $ show val ++ "\n" Leila Silva 18 Mais exemplos Ler n inteiros e devolver a lista de números lidos getList :: Int -> IO [Int] getList n = if n==0 then return [] else do x <- getInt xs <- getList (n-1) return (x:xs) main :: IO () main = do n <- getInt xs <- getList n putStr $ show xs ++ "\n" Leila Silva 19 Mais exemplos Ler n inteiros e devolver a lista de números lidos, na ordem inversa da leitura getListReversed :: Int -> IO [Int] getListReversed n = if n==0 then return [] else do xs <- getListReversed (n-1) x <- getInt return (x:xs) main :: IO () main = do n <- getInt xs <- getListReversed n putStr $ show xs ++ "\n" Leila Silva 20 Mais exemplos Ler n inteiros e devolver a lista de números lidos, na ordem inversa da leitura --a ação usa um acumulador como segundo argumento, onde os números lidos são guardados getListAcc :: Int -> [Int] -> IO [Int] getListAcc n xs = if n==0 then return xs else do x <- getInt getListAcc (n-1) (x:xs) main :: IO () main = do n <- getInt xs <- getListAcc n [] putStr $ show xs ++ "\n" Leila Silva 21 Mais exemplos Ler n inteiros e devolver a lista de números lidos positivos getList :: Int -> IO [Int] getList n = if n==0 then return [] else do x <- getInt xs <- getList (n-1) return (x:xs) main :: IO () main = do n <- getInt xs <- getList n putStr $ show (filter (>0) xs) ++ "\n" Leila Silva 22 Mais exemplos Ler n inteiros e devolver a lista de números lidos que são pares pares :: [Int]->[Int] pares [] = [] pares (x:xs) | even x = x: pares xs | otherwise = pares xs getList :: Int -> IO [Int] getList n = if n==0 then return [] else do x <- getInt xs <- getList (n-1) return (x:xs) main :: IO () main = do n <- getInt xs <- getList n let ps = pares xs putStr $ show ps ++ "\n" Leila Silva 23 Mais exemplos Ler n inteiros e devolver a lista de números lidos, ordenados em ordem crescente --a leitura cessa quando o número 0 for informado leEOrdena :: IO [Int] leEOrdena = do n <- getInt if n == 0 then return [] else do ns <- leEOrdena return (insOrd n ns) -- insOrd é a função usada na ordenação por inserção. insOrd x [] = [x] insOrd x (y:ys) | x <= y = x : y : ys | otherwise= y : insOrd x ys Leila Silva 24 1º Período Programação 3 25 Mais I/O No módulo System.IO readFile, writeFile, appendFile Tratamento de erros ioError Catch Monads ... 1º Período Programação 3 26 Leitura e Exercícios Recomendados Livro do Simon Thompson, capítulo 18 da segunda edição (Programming with actions), ou capítulo 8 na terceira edição (Playing the game: I/O in Haskell) Exercícios do capítulo 18 do Simon Thompson, segunda edição, ou do capítulo 8 na terceira edição. 1º Período Programação 3 27 Vídeos Recomendados Prof. Fernando Castor Monads e entrada e saída https://www.youtube.com/watch?v=Og3qKcJFOPc&list=PLnreHJ8o9y0-dWK-Q-0-qCV2b-NqpdTrz&index=14 Um pouco mais sobre monads https://www.youtube.com/watch?v=QZw6VEHTq5E&list=PLnreHJ8o9y0-dWK-Q-0-qCV2b-NqpdTrz&index=15
Compartilhar