livro texto (cap 11 e 9)
data Maybe a = Nothing | Just a
Resultado de algumas funções que podem não ter resultado
:m + Data.List
find (>4) [1,2,3,4,5,6,7]
find (>14) [1,2,3,4,5,6,7]
import Data.Map.Strict as M
let dd = M.fromList [("a",3),("b",5),("g",8)]
M.lookup "b" dd
M.lookup "f" dd
Um super tipo que contem um ou mais dados de um tipo interno (ou nenhum dado).
lista é um container que pode conter mais de um dado do tipo interno
Map é um container que pode conter mais do que um dado dos 2 tipos internos (chave - valor)
Maybe é um container que so contem um dado
O Just a
é o “valor correto” e Nothing
é o valor errado. Eu gostaria de poder continuar processando um Maybe enquanto o valor esta “correto”
fmap (*5) (Just 6)
fmap (*5) Nothing
Um container é um functor
se ele implementa a função fmap
:t fmap
:t map
fmap aplica uma função unária que funciona no dado de dentro, no container como um todo.
fmap é muito parecido com o map, ou na verdade, o container lista é um functor!!
O fmap aplica uma função que funciona no tipo de interno para dentro do container
Se voce esta definindo o container (tipo), vc precisa definir como o fmap funciona nele. O fmap do maybe é
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just something) = Just (f something)
Dicionario implementado como um abb
data Dic ch v = Vazio | No ch v (Dic ch v) (Dic ch v)
-- dicionario implmentado como uma ABB
instance Functor Dic where
fmap _ Vazio = Vazio
fmap f (No ch v ae ad) = No ch (f v) (fmap f ae) (fmap f ad)
Eu gostaria que:
(Just 7) + (Just 3) ==> Just 10
(Just 7) + Nothing ==> Nothing
Um container é um applicative
se ele permite aplicar uma função binaria que funciona no tipo interno e aplica-la em dois containers
Infelizmente a notação de um aplicative é esquisita. EU acho que isso deriva do fato que nao há funções binarias em haskell, só funções unárias.
(+) <$> (Just 7) <*> (Just 3)
(+) <$> (Just 7) <*> Nothing
o <$>
é um operador que combina uma funcao (do tipo interno) e um container e retorna “algo” O <*>
é outro operador que combina o “algo” com o container e retorna um container com os elementos internos sendo o resultado da aplicação da função binaria.
A lista é também é um applicative:
(+) <$> [1,2,3,4] <*> [10,100]
[11,101,12,102,13,103,14,104]
veja que o aplicative aplica a função binaria em todos os pares dos dois containers (o fmap aplica a função em todos so elementos do container)
Um container é uma monad
se ele implementa (entre outras coisas) a função infixa >>=
(operador de bind infixo ) que remove o dado de um container para aplica-lo em uma função que esta esperando o tipo interno e retorna um container com o resultado
:t (>>=)
(Just 8) >>= (\x -> if odd x then Nothing else (Just (2*x+1)) )
Listas são também monadas, que são combinadas com uma operacao de concatenação
[1,2,3] >>= (\x -> if odd x then [x] else [])
[4]
>>=
) como composicaopense em duas funçoes f :: a -> b
e g :: b -> c
uma coisa importante/central em programação funcional é compor essas funçoes
g (f x)
g $ f x
agora assuma uma função f'
que faz o que f
faz mas coloca o resultado num container (por exemplo o resultado e um log das operações)
g'
também gera um log.
mas como compor f'
e g'
?
é isso que o >>=
faz
f' x >>= g'
o >>=
é um tipo de composição de função. f' :: a -> t b
e g' :: b -> t c
onde t
é um container. Entao
f' x >>= g'
Monad define também a função return
que coloca um valor dentro do container
mae :: Pessoa -> Maybe Pessoa
pai :: Pessoa -> Maybe Pessoa
avomaternal p = return p >>= mae >>= pai
-- ou
avomaternal p = mae p >>= pai
Maybe é uma monada. Veja a definição dos dois operadores >>=
e return
instance Monad Maybe where
Nothing >>= f = Nothing
(Just x) >>= f = f x
return x = Just x
Monadas vão ser importantes. Todo o I/O vai ser relacionado com monadas mas ela é mais importante que isso.
do
é uma notação mais conveniente para monadas
avomaternal p = do
m <- mae p
pai m
A <-
retira o valor da monada.
A notação do parece um programa “tradicional” com o <-
como operador de atribuição
filtra f l = do
x <- l
if f x then [x] else []
filtra2 f l = [ x | x <- l, f x]
filtra odd [1,2,3,4]
filtra2 odd [1,2,3,4]
neste caso o do
faz um loop pela lista! O resultado de cada passo é uma lista ([x] ou []) e o bind da lista faz um concat
(concatena uma lista de listas)
concat [ [2], [], [1,2,3,4], [7,7], [], [] ]
Toda operação de I/O esta dentro da monada IO
:t getLine
:t putStrLn
getLine le uma linha e retorna o string dentro da monada IO
getContents le tudo
putStrLn recebe um string, imprime ele, e retorna uma tupla vazia dentro de IO
Uma forma genérica para programas haskell (sem interação)
main = do
dados <- getContent
let saida = proc dados
putStrLn saida
print
converte argumentos para string e imprime
show
apenas converte p/ string
read x :: Int
para converter um sting para inteiros
read x :: Float
para converter p/ float
funções lines
para quebrar um string em linhas e words
para quebrar uma linha nos brancos
funçoes unlines
e unwords
para montar o string final
..