2. Sobre mim
Sérgio Souza Costa
Professor - UFMA
Doutor em Computação Aplicada (INPE)
prof.sergio.costa@gmail.com
https://sites.google.com/site/profsergiocosta/home
https://twitter.com/profsergiocosta
http://gplus.to/sergiosouzacosta
http://www.slideshare.net/skosta/presentations?order=popular
3. John McCarthy
(Boston, 4 de setembro de 1927 — 23 de outubro de 2011)
Criador da linguagem Lisp, segunda linguagem de programação.
4. Life is too short for imperative
programming
John Hughes
“ “
9. POO Vs Funcional
Programação orientada a objetos é um estilo de Programação
que permite:
● Reuso de código (via classes)
● Eliminação de bugs (via encapsulamento, ocultação de
dados )
10. POO Vs Funcional
Programação funcional é um estilo de programação
que permite:
- Reuso de código (composição de função)
- Eliminação de bug (via imutabilidade (não existe mudança de
valores de variáveis))
11. Vantagens
● Códigos sucintos e concisos
○ Menor tempo de desenvolvimento
○ Manutenabilidade
● Códigos seguros
● Reusabilidade
● Facilidade de escrita, suporte a abstrações
● Confiabilidade, segurança
12. Exemplo - Quick sort (Haskell)
qs [] = []
qs (x:xs) = qs [y | y <- xs, y < x]
++ [x]
++ qs [y | y <- xs, y >= x]
13. Exemplo - Quick sort (C)
int particao(int vec[], int inicio, int
fim) {
int i, j;
i = inicio;
for (j = inicio + 1; j <= fim; ++j) {
if (vec[j] < vec[inicio]) {
++i;
troca(&vec[i], &vec[j]);
}
}
troca(&vec[inicio], &vec[i]);
return i;
}
14. Exemplo - Quick sort (C)
void quickSort(int vec[], int inicio,
int fim)
{
int p;
if (fim > inicio) {
p = particao(vec, inicio, fim);
quickSort(vec, inicio, p - 1);
quickSort(vec, p + 1, fim);
}
16. Conceitos chaves
● Expressões
● Funções
● Polimorfismo paramétrico
E em algumas linguagens:
● Abstração de dados
● Avaliação preguiçosa.
17. Conceitos chaves
● Expressão é um conceito chave, pois seu propósito é
computar novos valores a partir de valores antigos, que é a
essência da programação funcional.
● Função é um conceito chave, pois funções generalizam
expressões. Além disso, funções são valores de primeira
classe, dado que podem ser argumento e resultado de
outras funções, fazer parte de valores compostos ..
18. Conceitos chaves
Abstração de dados é o conceito chave nas linguagens funcionais modernas, tais
como ML e HASKELL. Permitem criar novos tipos de dados a partir dos já
existentes.
Polimorfismo paramétrico é um conceito chave, pois ele permite que uma função
opere sobre valores de uma família de tipos, ao invés de apenas um tipo. Na
prática, muitas funções são naturalmente polimórficas, e o polimorfismo
paramétrico incrementar o poder e a expressividade das linguagens funcionais
Avaliação preguiçosa é baseada na noção que uma expressão só será avaliada se
for usada.
19. Caso de Estudo: Haskell
Haskell: Uma abordagem prática:
Real World Haskell
●http://book.realworldhaskell.org/read/
20. Haskell
● Uma linguagem puramente funcional
● Funções puras
● Funções são valores de primeira ordem
● Linguagem com diversos recursos avançados:
● Casamento de padrões
● Compreensão de lista
● Avaliação preguiçosa
● Polimorfismo parametrico
25. Operadores
. Composição de funções
*, /, ^ multip, divisão, potência
+ , - adição, subtração
:, ++ composição de listas, concatenação
==,/=,<=,... igual, desigual, comparação
&& E
|| OU
26. Estratégia call-by-value --- Avalia primeiro o
argumento antes de aplicar a função
(Pascal, C, Java, etc).
Estratégia call-by-name (ou AVALIAÇÃO
PREGUIÇOSA) --- Aplica imediatamente a
função ao argumento, adiando para mais
tarde a avaliação desse argumento (Haskell
e Miranda)
Estatégias de avaliação
27. Tipos em Haskell
O que é um tipo?
Tipo é um conjunto de valores que possuem um comportamento uniforme
sobre dadas operações. (David Watt)
“A program variable can assume a range of values during the execution of
a program. An upper bound of such a range is called a type of the variable”
(Cardelli)
28. Tipos em Haskell
Tipo é uma restrição
Descreve os limites do resultado final de uma computação
“The fundamental purpose of a type system is to prevent the
occurrence of execution errors during the running of a
program” (Cardelli).
29. Tipos primitivos
●Bool Boleanos
●Char Caracteres
●Int Inteiros de 32-bits
●Integer Inteiros de tam ilimitado
●Float Ponto flutuante
●Double Dupla precisão
30. Toda expressão tem um tipo
Os tipos podem ser inferidos
Prelude> :t (4 > 5)
(4 > 5) :: Bool
Prelude> :t (5+4)
(5+4) :: (Num t) => t
Prelude> :t [1.2,5.0]
[1.2,5.0] :: (Fractional t) => [t]
31. Função
● Correspondência biunívoca de membros do conjunto domínio para membros
do conjunto imagem
● Ordem de avaliação de suas expressões é controlada por expressões
condicionais
○ Não pela seqüência ou pela repetição iterativa
● Não têm efeitos colaterais
○ Sempre definem o mesmo valor dado o mesmo conjunto de argumentos, diferentemente de
um procedimento em linguagens imperativas.
32. Função
● Nome lista de parâmetros = expressão de correspondência
○ cubo x = x * x * x
● Um elemento do conjunto imagem é obtido para cada par: Nome da
função + um elemento particular do conjunto domínio
○ cubo 2.0 = 8.0
● Definição de uma função separada da tarefa de nomeá-la
○ Notação lambda (Church, 1941)
○ λ(x) x * x * x
33. f1 :: Int → Int → Int
f1 x y = x*y
Função
● A definição de uma função deve obedecer a sintaxe seguinte:
nome_função :: tipo_arg1 -> ... -> tipo_argN -> tipo_saída
nome_função arg1 ... argN = <expressão_resultado>
● Sendo tipo1,...,tipoN os tipos dos parâmetros de entrada da função.
34. Matemática
f (x)
f (x,y)
f (g(x))
f (x, g(y))
f (x) g(y)
f(a,b) + c d
Haskell
f x
f x y
f (g x) ou f $ g x
f x (g y) ou f $ g y
f x * g y
f a b + c * d
Função
35. Funções como valores de primeira classe
Significa que as funções têm um estatuto tão importante como o dos inteiros, reais,
e outros tipos predefinidos. Concretamente, numa linguagem funcional as funções
podem ...
● Ser passadas como argumento para outras funções;
● Podem ser retornadas por outras funções;
● Podem ser usadas como elementos constituintes de estruturas de dados;
Prelude>map (x->2*x) [1,2,3]
[2,4,6]
36. Expressão de seleção (ou condicional)
menor x y =
se x <= y então o resultado da expressão é x
senão o resultado é y
Considere uma função que dado dois valores, retorna o menor:
A estratégia para resolução do problema é com uso de uma expressão de seleção
37. Expressão de seleção
if <condição> then <resultado 1>
else <resultado2>
menor :: Int -> Int -> Int
menor x y = if x <= y then x
else y
38. -- fatorial
fat :: Integer -> Integer
fat 0 = 1
fat n = fat (n-1) * n
Casamento de padrões
Podemos especificar o comportamento de uma função descrevendo sua resposta
a diferentes situações de entrada.
● Podemos ter múltiplas definições
● Alternativa aos “ifs”
39. Listas
● Uma lista é uma sequência de valores ordenados
● Listas são homogêneas:
●todos os elementos da lista tem o mesmo tipo
● Listas são dinâmicas:
●não há restrição no tamanho de listas (incluindo listas infinitas)
40. Listas
Uma lista é composta sempre de dois segmentos: cabeça
(head) e corpo (tail). A cabeça é sempre o primeiro emento e
corpo é uma lista com os demais elementos.
Prelude> ['a','b','c','d']
"abcd"
Prelude> 'a':['b','c','d']
"abcd"
41. Listas em Haskell
●
● Três tipos de notação:
● construtores:
1 : 1 : 2 : 3 : 5 : 8 : []
● “colchetes":
[1, 1, 2, 3, 5, 8]
● strings (apenas para listas de caracteres):
['h', 'e', 'l', 'l', 'o'] = "hello"
42. Listas
Pode se definir uma lista indicando os limites inferior e superior:
[<limite-inferior> .. <limite-superior>]
43. Listas
Podemos definir qualquer progressão aritmética em uma lista utilizando a
seguinte notação:
[<termo1>, <termo2> .. <limite-superior>
Prelude> [0,3..21]
[0,3,6,9,12,15,18,21]
Prelude> [0,2..20]
[0,2,4,6,8,10,12,14,16,18,20]
44. Listas por compreensão
A definição de listas por compreensão é feita por um construtor de listas
que utiliza conceitos e notações da teoria dos conjuntos. Assim, para um
conjunto A temos:
Sendo E(x) uma expressão em X, onde X pertence a lista, dados um
conjunto de proposições Pi(x)
A = [E(x) | x <- lista, P1(x), ..., Pn(x)]
Por exemplo:
[x | x <- l1, even x, x < 100 ], todos pares menos que 100 pertencentes a l1
45. Compreensão de listas
● Um construtor de processamento de listas em linguagem de programação, a
notação matemática é a seguinte:
● Outros exemplos
● Por exemplo, as 10 primeiras potências de 2:
[2 ^ x | x <- [1..10] ]
● Todos os números pares maiores que 1 e menores que 100:
[ x | x <- [1..100] , par x ]
46. Exemplo:
[x | x <- [1..1000], even x, x < 100 ]
[2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,
46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,8
4,86,88,90,92,94,96,98]
Compreensão de listas
49. Recursão
length :: [a] -> Int
length [] = 0
length (x : xs) = 1 + length xs
Um conceito básico em Haskell é o uso de recursão para
definição de funções
50. Recursão
● Sem loops explícitos, o fluxo em Haskell é usualmente expresso por recursão.
● Como garantir que recursão termine?
○ Escolha uma “entidade” para focar o processo
○ Garanta que a próxima chamada estará mais próxima de uma condição de
término
Exemplos:
● Decrementar um valor para cada chamada
● Tomar um valor de uma lista a cada chamada
51. Recursão
●
A soma dos números de uma lista vazia
sumAll (x : xs) = x + sumAll xs
sumAll [] = 0
sumAll :: [Integer] -> Integer
Soma de todos os números de uma lista
Soma dos números de uma lista x : xs
52. Recursão
●
Concatenar uma lista vazia:
concat (s : ss) = s ++ concat ss
concat [] = [] --- = “”
concat :: [[Char]] -> [Char]
Concatenação de listas de caracteres
Concatenar uma lista a partir de um elemento:
54. Recursos avançados
●
1. Definições locais,
2. Importando bibliotecas externas,
3. Funções de segunda ordem
4. Trabalhando com entrada e saída
54
55. Definições locais
raizes (a, b, c) = (x1,x2)
where
delta = sqrt ( b^2 - 4*a*c)
x1 = ((-b) + delta) / (2*a)
x2 = ((-b) - delta) / (2*a)
55
Para uma melhor legibilidade de um código, podemos usar a
cláusula “where” para fazer definições visíveis somente por
uma dada função.
56. Sinônimos
type Point = (Int, Int)
type Polygon = [Point]
p1 :: Point
p1 = (1,4)
pol1:: Polygon
pol1 = [(1,1),(1,2),(3,1),(1,1)]
56
Em Haskell, é possível criar sinônimos de tipos, ex:
57. Avaliação parcial
57
Haskell distingue entre operadores and funções:
Operadores têm noção infixa (e.g. 1 + 2),
Funções usam notação prefixa (e.g. plus 1 2).
Operadores podem ser convertidos em funções colocando-os entre parênteses:
(+) m n = m + n.
Haskell aceita operadores com avaliação parcial. E.g.:
(+ m) n = m + n
(: 0) l = 0 : l
58. Avaliação parcial
multThree :: (Num a) => a -> a -> a -> a
multThree x y z = x * y * z
ghci> let multTwoWithNine = multThree 9
ghci> multTwoWithNine 2 3
54
ghci> let multWithEighteen =
multTwoWithNine 2
ghci> multWithEighteen 10
180
58
59. Avaliação parcial
divideByTen :: (Floating a) => a -> a
divideByTen = (/10)
59
A função divideByTen 200 é equivalente a 200 / 10, ou (/10)
200
60. Funções são valores de primeira classe
60
● Em linguagens funcionais, funções são valores de primeira classe.
● Não existe restrição sobre o uso de funções em linguagens funcionais,
● Podem ser argumentos de funções
● Saídas de funções
● Elementos de estrutura de dados
61. Funções como argumentos
twice :: (a -> a) -> a -> a
twice f x = f (f x)
61
Uma característica poderosa de Haskell é funções podem ser argumentos de
outras funções.
Estas funções são chamadas funções de segunda ordem.
62. Map
map :: (a -> b) -> [a] -> [b]
Main> map double [1,3,5,7]
[2,6,10,14]
62
A função map aplica uma função a todos os elementos de
uma lista.
63. Map pode ser definido por recursão ou por compreensão de
listas
Ou por compreensão de lista
Map
map :: (a -> b) -> [a] -> [b]
map f xs = [f x | x xs]
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x : xs) = (f x) : map f xs
63
66. Filter
filter :: (a -> Bool) -> [a] -> [a]
Main> filter even [1..10]
[2,4,6,8,10]
66
A função filter seleciona os elementos de uma lista que
satisfazem a um predicado
67. Filter
filter :: (a -> Bool) -> [a] -> [a]
filter p xs = [x | x <- xs, p x]
filter p [] = []
filter p (x : xs)
| p x = x : filter p xs
| otherwise = filter p xs
67
Pode ser definido como compreensão de listas ou por recursão
68. Comprimindo para um único valor
f [] = v
f (x:xs) = x <- f xs
68
Um grande número de funções em listas podem ser definidas a partir de um
padrão simples de recursão
●A lista vazia recebe para um valor final, e uma lista
●não vazia é mapeada para um operador : que
●combina o primeiro elemento com a aplicação da função no resto da lista
69. Comprimindo para um único valor
sum [] = 0
sum (x:xs) = x + sum xs
product [] = 1
product (x:xs) = x * product xs
and [] = True
and (x:xs) = x && and xs
11/4/11 69
70. Comprimindo para um único valor
sum = foldr (+) 0
product = foldr (*) 1
and = foldr (&&) True
70
A função foldr (“fold right”) encapsula este padrão de recursão em listas, com a
função dada e o valor v como argumentos
71. Definição do foldr
foldr::(a -> b -> b) -> b -> [a] -> b
foldr f v [] = v
foldr f v (x:xs) =
f x (foldr f v xs)
71
73. Abstração de dados
73
Tipos enumerados (enumerated no C),
Tipos cartesianos (struct no C),
Uniões disjunta (union no C)
Tipos recursivos
74. O que vimos até então...
type Matricula = Int
type Nome = String
type Salario = Double
type Funcionario = (Matricula, Nome, Salario)
74
Usamos os tipos existentes em Haskell
● Primitivos: Int, String, Bool
● Compostos: Listas e tuplas
Aprendemos criar sinônimos :
76. Qual o problema com os sinônimos?
76
type Matricula = Int
type Nome = String
type Salario = Double
type Funcionario = (Matricula, Nome, Salario)
funcionarios :: [Funcionario]
funcionarios = [(1235,"joao", 580), (256,"jose", 590)]
aumentaSalario :: Funcionario -> Funcionario
aumentaSalario (m,n,s) = (m,n,s+(0.1*s))
type Nota = Double
type Alunos = (Matricula, Nome, Nota)
alunos :: [Alunos]
alunos = [(1,"antonio", 50.6), (6,"maria", 70)]
– eu poderia aplicar aumentaSalario a um aluno, pois são a mesma tupla,
– apenas com nomes diferentes
77. Usando tipos algébricos do Haskell
Data Funcionario = Funcionario Int String Double
type Matricula = Int
type Nome = String
type Salario = Double
Data Funcionario = Funcionario Matricula Nome Salario
Nós definimos um novo tipo de dado usando o
palavra-chave data.
78. Tipos Compostos
78
Os tipos algébricos do Haskell permite estruturas diversos tipos a partir de valores
mais simples.
● Produto cartesiano ( registros)
● Tipos enumerados
● Uniões disjuntas (variantes e uniões)
● Tipos recursivos (estruturas de dados dinâmicas)
79. Tipos algébricos
data InfoLivro = Livro Int String [String]
Nome do tipo
Construtor de tipo
Diferenças entre nome de tipos e construtor de tipos:
O nome do tipo e dos construtores não precisa ser iguais.
80. Tipos algébricos
data Matricula = Matricula Int
deriving (Show, Ord, Eq)
Palavra chave
para derivar
classes
80
O Haskell dispõe diversas classes que podem ser derivadas para os novos
tipos.
●Show, permite vizualizar os dados na tela
●Ord, permite fazer comparaçoes, < e >
●Eq, permite verificar se dois tipos são iguais
81. Tipos algébricos – Registro
struct Point {
x,y: double;
};
data Point = Pt Double Double
deriving (Show)
C
Haskell
81
82. Tipos algébricos – Registro
data Point = Pt Double Double
deriving (Show)
getX :: Point → Double
getx Pt x y = x
getY :: Point → Double
getY Pt x y = x
82
Usando casamento de padrão para pegar um dado valor
83. Enumerandos
enum Dias {Segunda, Terça, Quarta,
Quinta, Sexta}
data Dias = Segunda | Terça | Quarta
| Quinta | Sexta deriving (Show)
C
Haskell
83
84. Tipo Booleano
data Booleano = Falso | Verdadeiro deriving (Show, Eq)
e :: Booleano -> Booleano -> Booleano
e Falso _ = Falso
e Verdadeiro b = b
maior :: Int -> Int -> Booleano
maior a b
| a > b = Verdadeiro
| otherwise = Falso
-- a é maior que b e c
maior3 a b c = (maior a b) `e` (maior a c)
-- maior3 7 5 6
84
85. União Disjunta em Haskell
data Number = Exact Int | Inexact Float
Valores:
Number = Exact Integer + Inexact Float
… Exact(–2) Exact(–1) Exact 0 Exact 1 Exact 2 …
… Inexact(–1.0) … Inexact 0.0 … Inexact 1.0 …
Cada valor consiste de uma tag, junto ou com
um valore inteiro (se a tag is Exact) ou um
valor Float (se a tag é Inexact).
85
86. Exemplo de união disjunta
data Number = Exact Int | Inexact Float deriving (Show)
pi2 = Inexact 3.1416
rounded :: Number -> Int
rounded (Exact i) = i
rounded (Inexact r) = round r
86
87. União Disjunta – Tratando erro
data Maybe a = Nothing | Just a
87
Em Haskell existe um tipo de dado muito util em casos onde uma função pode não
ter retorno.
●ex. buscar um elemento em uma lista
type Aluno = (Int, String)
busca :: Int -> [Aluno] -> Maybe String
busca mat [] = Nothing
busca mat ((x,y):xys)
| mat == x = Just y
| otherwise = busca mat xys
91. Tipos recursivos
data Nat = Zero | Succ Nat deriving (Show)
soma :: Nat -> Nat -> Nat
soma Zero n = n
soma (Succ m) n = Succ (soma m n)
mult :: Nat -> Nat -> Nat
mult Zero m = Zero
mult (Succ m) n = soma n (mult n m)
91
92. Tipos Recursivos - Lista
data List =
Nil |
Cons Int List
deriving (Show)
first (Cons a s) = a
first Nil = error "vazio"
rest (Cons a s) = s
rest Nil = error "vazio"
92
95. ● Uma característica importante de Haskell é o uso de tipos paramétricos
● Muitas funções podem ser definidas em termos de tipos genéricos
● Convenção: usamos a, b, c para tipos genéricos
● Tipos paramétricos comuns, listas e tuplas
length :: [a] → Int
Tipos Paramétricos em Haskell
Pode ser lista de inteiros, de listas ..
95
96. data List a =
Nil |
Cons a List
deriving (Show)
first :: List a → a
first (Cons a s) = a
first Nil = error "vazio"
rest :: List a → List a
rest (Cons a s) = s
rest Nil = error "vazio"
data List Int =
Nil |
Cons Int List
deriving (Show)
first :: List → Int
first (Cons a s) = a
first Nil = error "vazio"
rest :: List → List
rest (Cons a s) = s
rest Nil = error "vazio"
Lista de inteiros Lista paramétrica
96
Tipos Paramétricos em Haskell
97. data ArvBin a = Vazia | Nodo a (ArvBin a) (ArvBin a)
deriving Show
elem :: ArvBin a -> a
elem Vazia = error "arvore vazia"
elem (Nodo e _ _) = e
esq :: ArvBin a -> ArvBin a
esq Vazia = error "arvore vazia"
esq (Nodo _ e _) = e
dir :: ArvBin a -> ArvBin a
dir Vazia = error "arvore vazia"
dir (Nodo _ _ d) = d
97
Tipos Paramétricos em Haskell
98. Definindo as funções de acesso
diretamente na definição
data ArvBin a = Vazia |
Nodo {
elem :: a,
esq :: (ArvBin a),
dir :: (ArvBin a)
} deriving Show
98
100. Restrição no polimorfismo
somatodos :: (Num a) => [a] -> a
somatodos (x:xs) = x + somatodos xs
100
Usando “type classes
A função somatodos funciona sobre qualquer “a”, desde que ele seja um Num.
101. Type class em Haskell
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
101
●Uma classe é uma coleção de tipos que suportam certas operações (métodos)
comuns
●Uma classe define uma assinatura, similar a uma interface
102. Classes Básicas em Haskell
Eq - tipos com igualdade
Ord – tipos ordenados
Show – tipos que podem ser transformados em strings
Read – tipos legíveis, que pode ser convertido
Num – tipos numéricos
102
103. Instanciando type class
data Point = Point Int Int deriving (Show, Eq, Ord,
Read)
instance Num Point where
(+) (Point x1 y1) (Point x2 y2)
= Point (x1 + x2) (y1 + y2)
103
104. data Point = Point Int Int
instance Show Point where
show (Point x y) = show (x,y)
Prelude> Point 4 5
> (4,5)
104
Instanciando type class
● Podemos instanciar qualquer uma das classes pré definidas, mesmo as
que são deriváveis, como Read, Show ...
106. Operações de entrada e saída
106
Até então, vimos como usar o Haskell via ghci, mas como
gerar um programa compilável?
Como o Haskell consegue lidar com operações de entrada e
saída ?
Esse tipo de operação tem efeitos colaterais.
107. O problema ...
Um programa em
Haskell consiste
num conjunto de
funções, sem
efeitos colaterais
O objetivo de
executar qqer
programa é ter
algum efeito
colateral
Tensão
107
108. A solução
IO a
O tipo das ações de IO que retornam
um valor do tipo a
108
Escrever programas interativos em Haskell usando tipos que fazem
distinção entre expressões funcionais “puras” de ações “impuras” que
podem envolver efeitos colaterais
109. I/O em Haskell
IO Char
IO ()
O tipo das ações de IO que retornam
um caracter
O tipo das ações que não tem valor
de retorno
109
110. IO em Haskell: O tipo (IO a)
Um valor do tipo (IO t) é uma ação que, quando realizada, pode
fazer alguma forma de IO antes de devolver um resultado do
tipo t.
type IO a = World -> (a, World)
IO a
World outWorld in
result::a
110
111. Meu Primeiro Programa
Ou, compile em código nátivo.
module Main where
main = putStrLn "Hello World!"
runghc hello.hs
Hello World!
ghc hello.hs -o prg1
./prg1
Hello World!
111
Para rodar interpretado use o runghc:
112. Funções da biblioteca
112
Funções para escrever na tela
putStr :: String -> IO ()
putStrLn :: String -> IO ()
Para ler uma linha de caracteres do teclado, podemos usar a função:
getLine :: IO(String)
114. Meu segundo programa
module Main where
main = do
input <- getLine
putStrLn input
114
Lê uma entrada do usuário e imprime na tela
115. Meu terceiro programa
module Main where
ask :: String -> IO String
ask question = do
putStrLn question
getLine
main :: IO ()
main = do
nome <- ask "Qual eh o seu nome? "
matr <- ask "Qual eh a sua matricula?"
putStrLn ("Benvindo "++ nome ++ "!")
putStrLn ("Sua matricula eh "++matr)
115
116. Trabalhando com arquivos
import IO
import Data.Char
main = do
str <- readFile "input.txt"
writeFile "output.txt" (map toUpper str)
116
Converte todo um arquivo texto para letras maiúsculas.
A função readfile retorna uma string contendo todo o arquivo e writeFile escreve
uma string em um arquivo.
117. Funções para string
117
Função lines, quebra uma string pelo marcador de fim de linha
lines “linha1nlinha2”
= [“linha1”,linha 2]
Função words, quebra uma string por separador de palavras,”espaço”.
words “uma frase”
= [“uma”, frase]
118. Trabalhando com arquivos
main = do
str <- readFile "input.txt"
print (length (words str))
print (length (lines str))
118