Aula 9

livro texto (cap 11 e 9)

Haskell online

Haskell - compilado

Maybe

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

Funções do Maybe

Maybe no hackage

Containers

Um super tipo que contem um ou mais dados de um tipo interno (ou nenhum dado).

Maybe como container

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

Functor

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)

applicative

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)

monad

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]

bind (>>=) como composicao

pense 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'

return

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

Notação do

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], [], [] ]

I/O

Toda operação de I/O esta dentro da monada IO

:t getLine

:t putStrLn

Uma forma genérica para programas haskell (sem interação)

main = do 
       dados <- getContent
       let saida = proc dados
       putStrLn saida

..