46
Desvendando os mistérios das Mônades Aprenda a domar os efeitos colaterais com Mônades em Haskell

TDC2016SP - Trilha Programação Funcional

Embed Size (px)

Citation preview

Page 1: TDC2016SP - Trilha Programação Funcional

Desvendando os mistérios das MônadesAprenda a domar os efeitos colaterais com Mônades em Haskell

Page 2: TDC2016SP - Trilha Programação Funcional

Sobre o palestrante

Eduardo Sato

Engenheiro de Computação (Poli USP 2004)

Consultoria, desenvolvimento Java, C++, python, perl, Haskell, C etc

Músico amador: violão

Linguagens de programação, programar emuladores, compiladores

Page 3: TDC2016SP - Trilha Programação Funcional

Pesquisa

- Quem aqui programa em Haskell?- Quem aqui usa/conhece Mônades em Haskell ou outra linguagem?- Palestra do Roberto "Haskell 101"

Page 4: TDC2016SP - Trilha Programação Funcional

Quantidade de tutorias de Mônades

https://wiki.haskell.org/Monad_tutorials_timeline

Page 5: TDC2016SP - Trilha Programação Funcional

A falácia do Tutorial de Mônades

Page 6: TDC2016SP - Trilha Programação Funcional

Mônades?

Page 7: TDC2016SP - Trilha Programação Funcional

Mônade: definição

Uma mônade nada mais é que: “um monóide na categoria dos endofunctores”

Page 8: TDC2016SP - Trilha Programação Funcional

Problem?

Page 9: TDC2016SP - Trilha Programação Funcional

A falácia do Tutorial de Mônades

- Aprendizado: começar com o concreto e ir ao abstrato- Seres humanos: bons em reconhecimento de padrões- Mônades, OO etc: aprendizado não linear e dependências circulares- Momento “a-ha!”- No caso das mônades: vários momentos “a-ha!”

Page 10: TDC2016SP - Trilha Programação Funcional

Pureza

Linguagens funcionais

- Puras: Miranda, Haskell- Impuras: Scheme, F#, Standard ML etc

Pureza:

- Trânsparência referencial- Fácil de analisar- Preguiça (laziness) manteve a Haskell pura

Page 11: TDC2016SP - Trilha Programação Funcional

Entrada / Saída / Efeitos

Programas compostos por funções matemáticas:

Como fazer entrada/saída/efeitos colaterais?

Qual é a utilidade de um programa totalmente puro?

Page 12: TDC2016SP - Trilha Programação Funcional

Mônades em programação funcional

Aplicações:

- Descrever computações componíveis (?) (1)- Sequência: Separação da linha do tempo da computação composta da

linha do tempo de excecução (2)- Contexto: Implicitamente carregar dados extras (contexto), pertinentes à

computação em si, além do seu resultado (3)- Suplementar cálculos puros com E/S, ambiente, estado etc (4)- E muito mais!

Page 13: TDC2016SP - Trilha Programação Funcional

Expressividade: SICP - Abel & Sussman

Linguagens servem como framework pelo qual organizamos nossas ideias sobre processos

Uma linguagem de programação poderosa possui:

- Expressões primitivas- Meios de combinação: pelos quais elementos compostos são construídos

a partir de elementos mais simples- Meios de abstração: pelos quais elementos compostos podem ser

nomeados e manipulados de maneira unitária

Page 14: TDC2016SP - Trilha Programação Funcional

Haskell: curso relâmpago

Assinatura

Definição

Chamada de função

Definição de Tipo

Polimorfismo paramétrico

f 1 g "foo" "bar"

f :: Int -> Int g :: String -> String -> String

f n = n + 1 g a b = a ++ b

data Naipe = Paus | Copas | Espada | Ouro deriving Show

length :: [a] -> Int

Page 15: TDC2016SP - Trilha Programação Funcional

Haskell: curso relâmpago

Descontstrução

data Maybe a = Just a | Nothing

foo = Just "Foo"

nada = Nothing

segredo = Just 42

showMaybe :: (Show a) => Maybe a -> String

showMaybe (Just x) = "Just " ++ show x

showMaybe Nothing = "Nothing"

ghci> showMaybe foo

"Just Foo"

ghci> showMaybe nada

"Nothing"

ghci> showMaybe segredo

"Just 42"

Page 16: TDC2016SP - Trilha Programação Funcional

Motivação: um simples avaliador:Tema e variações

Tema: o avaliador básico

data Termo = Const Int | Div Termo Termo deriving (Show)avaliar :: Termo -> Intavaliar (Const n) = navaliar (Div t n) = avaliar t `div` avaliar n

expr = Div (Div (Const 1932) (Const 2)) (Const 23)

divisaoPorZero = Div (Const 1) (Const 0)

resposta = avaliar exprerro = avaliar divisaoPorZero

Div

Div Const

23Const

1932

Const

2

Div

Const

1

Const

0

Page 17: TDC2016SP - Trilha Programação Funcional

Tema: resultado

ghci> resposta

42

ghci> erro

*** Exception: divide by zero Ops!

Page 18: TDC2016SP - Trilha Programação Funcional

Variação 1

Tratamento de Erros

data Termo = Const Int | Div Termo Termo deriving (Show)data M a = Valor a | Exc String deriving (Show)

avaliar :: Termo -> M Intavaliar (Const n) = Valor navaliar (Div t u) = case avaliar t of Exc e -> Exc e Valor a -> case avaliar u of Exc e -> Exc e Valor b -> if b == 0 then Exc "divisao por zero" else Valor (a `div` b)

Page 19: TDC2016SP - Trilha Programação Funcional

Resultado

ghci> resposta

Valor 42

ghci> erro

Exc "divisao por zero"

Page 20: TDC2016SP - Trilha Programação Funcional

Variação 2: prelúdio

Composição de lambdas para carregar estado:

:: \s -> (Int, s)

Podemos agregar computações que “alteram” o estado e produzem

resultados parciais em uma única computação que produz um resultado

final e um estado

s: estado Int: resultado

Lambda: uma computação que recebe um estado produzindo um resultado e um novo estado

O resultado (Int) pode ser calculado através de um valor do fechamento (closure)

Page 21: TDC2016SP - Trilha Programação Funcional

Variação 2

Estado: contar o número de divisões

data Termo = Const Int | Div Termo Termo deriving (Show)data M a = Estado { obterEstado :: (Int -> (a, Int)) }

avaliar :: Termo -> M Intavaliar (Const a) = Estado (\x -> (a, x))avaliar (Div t u) = Estado $ \x -> let (a, y) = obterEstado (avaliar t) x (b, z) = obterEstado (avaliar u) y in (a `div` b, z + 1)

expr = Div (Div (Const 1932) (Const 2)) (Const 23)

resposta = obterEstado (avaliar expr) 0

obterEstado x: descasca o valor de M obtendo a função encapsulada

Page 22: TDC2016SP - Trilha Programação Funcional

Resultado

ghci> resposta

(42,2)

Page 23: TDC2016SP - Trilha Programação Funcional

Variação 3

Saída: imprimir log

data Termo = Const Int | Div Termo Termo deriving (Show)data M a = Saida (String, a) deriving (Show)

avaliar :: Termo -> M Intavaliar (Const a) = Saida (imprimirLinha (Const a) a, a)avaliar (Div t u) = let Saida (x, a) = avaliar t Saida (y, b) = avaliar u in Saida (x ++ y ++ imprimirLinha (Div t u) (a `div` b), a `div` b)

imprimirLinha :: Termo -> Int -> StringimprimirLinha t a = show t ++ " = " ++ show a ++ "\n"

Page 24: TDC2016SP - Trilha Programação Funcional

Variação 3 - Cont.

expr = Div (Div (Const 1932) (Const 2)) (Const 23)

Saida (saida, resposta) = avaliar expr

Page 25: TDC2016SP - Trilha Programação Funcional

Resultado

ghci> putStr saida

Const 1932 = 1932

Const 2 = 2

Div (Const 1932) (Const 2) = 966

Const 23 = 23

Div (Div (Const 1932) (Const 2)) (Const 23) = 42

ghci> print resposta

42

Page 26: TDC2016SP - Trilha Programação Funcional

Mônades: o que são

Na prática (em Haskell):

- Uma declaração de tipo parametrizado em a para representar computações:

- data M a = ...

- Função return: transformar valores a em computações:- return :: a -> M a (sem efeitos, exceções, log, mudar estado)

- Uma maneira de combinar computações- Operador bind: (>>=) :: M a -> (a -> M b) -> M b

m k

Page 27: TDC2016SP - Trilha Programação Funcional

Leis

- Identidade:- return a >>= f = f a

- m >>= return = m

- Associatividade:- (m >>= f) >>= g = m >>= (\x -> f x >>= g)

Page 28: TDC2016SP - Trilha Programação Funcional

Tema revisitado

Mônade Identidade

data Termo = Const Int | Div Termo Termo deriving (Show)data Identity a = Identity a deriving (Show)

instance Monad Identity where return x = Identity x (Identity a) >>= k = k a

avaliar :: Termo -> Identity Intavaliar (Const a) = return aavaliar (Div t u) = avaliar t >>= \a -> avaliar u >>= \b -> return (a `div` b)

avaliar t >>= (\a -> avaliar u >>= (\b -> return (a `div` b)))

Page 29: TDC2016SP - Trilha Programação Funcional

Tema revisitado

expr = Div (Div (Const 1932) (Const 2)) (Const 23)

resposta = avaliar expr

ghci> resposta

Identity 42

Page 30: TDC2016SP - Trilha Programação Funcional

Variação 1 revistada

Exceções

data Termo = Const Int | Div Termo Termo deriving (Show)data Exception a = Raise String | Return a deriving (Show)

instance Monad Exception where return x = Return x (Raise e) >>= f = Raise e (Return a) >>= f = f a

raise :: String -> Exception araise e = Raise e

Page 31: TDC2016SP - Trilha Programação Funcional

Variação 1 revistada

avaliar :: Termo -> Exception Intavaliar (Const a) = return aavaliar (Div t u) = avaliar t >>= \a -> avaliar u >>= \b -> if b == 0 then raise "divisao por zero" else return (a `div` b)

expr = Div (Div (Const 1932) (Const 2)) (Const 23)divisaoPorZero = Div (Const 1) (Const 0)

resposta = avaliar exprerro = avaliar divisaoPorZero

Page 32: TDC2016SP - Trilha Programação Funcional

Resultado

ghci> resposta

Return 42

ghci> erro

Raise "divisao por zero"

Page 33: TDC2016SP - Trilha Programação Funcional

Variação 2 revistada

data Termo = Const Int | Div Termo Termo deriving (Show)data State a = State { runState :: (Int -> (a, Int)) }

instance Monad State wherereturn x = State (\s -> (x, s))m >>= k = State (\x -> let (a, y) = runState m x

(b, z) = runState (k a) y in (b, z))

tick :: State ()tick = State (\s -> ((), s + 1))

Page 34: TDC2016SP - Trilha Programação Funcional

Variação 2 revistada

avaliar :: Termo -> State Intavaliar (Const a) = return aavaliar (Div t u) = avaliar t >>= \a -> avaliar u >>= \b -> tick >>= \_ -> return (a `div` b)

expr = Div (Div (Const 1932) (Const 2)) (Const 23)resposta = runState (avaliar expr) 0

Page 35: TDC2016SP - Trilha Programação Funcional

Resultado

ghci> resposta

(42,2)

Page 36: TDC2016SP - Trilha Programação Funcional

Variação 3 revistada

data Termo = Const Int | Div Termo Termo deriving (Show)data Writer a = Writer { runWriter :: (String, a) } deriving (Show)

instance Monad Writer wherereturn x = Writer ("", x)Writer (x, a) >>= k = let Writer (y, b) = k a

in Writer (x ++ y, b)

output :: String -> Writer ()output s = Writer (s, ())

imprimirLinha :: Termo -> Int -> StringimprimirLinha t a = show t ++ " = " ++ show a ++ "\n"

Page 37: TDC2016SP - Trilha Programação Funcional

Variação 3 revistada

avaliar :: Termo -> Writer Intavaliar (Const a) = output (imprimirLinha (Const a) a) >>= \_ -> return aavaliar (Div t u) = avaliar t >>= \a -> avaliar u >>= \b -> output (imprimirLinha (Div t u) (a `div` b)) >>= \_ -> return (a `div` b)

expr = Div (Div (Const 1932) (Const 2)) (Const 23)Writer (saida, resposta) = avaliar expr

Page 38: TDC2016SP - Trilha Programação Funcional

Resultado

ghci> putStr saida

Const 1932 = 1932

Const 2 = 2

Div (Const 1932) (Const 2) = 966

Const 23 = 23

Div (Div (Const 1932) (Const 2)) (Const 23) = 42

ghci> resposta

42

Page 39: TDC2016SP - Trilha Programação Funcional

Notação do

ma >>= \a ->

mb >>= \b ->

mc >>= \c ->

return x

do a <- ma

b <- mb

return x

ma >>= (\a -> mb >>= (\b -> mc >>= (\c -> return x)))

Page 40: TDC2016SP - Trilha Programação Funcional

Açúcar sintático - Exception

avaliar :: Termo -> Exception Int

avaliar (Const a) = return a

avaliar (Div t u) = do a <- avaliar t

b <- avaliar u

if b == 0

then raise "divisao por zero"

else return (a `div` b)

avaliar :: Termo -> Identity Int

avaliar (Const a) = return a

avaliar (Div t u) = do a <- avaliar t

b <- avaliar u

return (a `div` b)

Page 41: TDC2016SP - Trilha Programação Funcional

Açúcar sintático

avaliar :: Termo -> State Int

avaliar (Const a) = return a

avaliar (Div t u) = do a <- avaliar t

b <- avaliar u

tick

return (a `div` b)

avaliar :: Termo -> Identity Int

avaliar (Const a) = return a

avaliar (Div t u) = do a <- avaliar t

b <- avaliar u

return (a `div` b)

Page 42: TDC2016SP - Trilha Programação Funcional

Açúcar sintático - Writer

avaliar :: Termo -> Writer Int

avaliar (Const a) = do output (imprimirLinha (Const a) a)

return a

avaliar (Div t u) =

do a <- avaliar t

b <- avaliar u

output (imprimirLinha (Div t u) (a `div` b))

return (a `div` b)

avaliar :: Termo -> Identity Int

avaliar (Const a) = return a

avaliar (Div t u) = do a <- avaliar t

b <- avaliar u

return (a `div` b)

Page 43: TDC2016SP - Trilha Programação Funcional

Outras Mônades

- Par: paralelismo- Lista: não determinismo- Cont: continuações- Parsec: parsers- IO- Lógica- Probabilidade- Free Monads -> DSLs- etc

Page 44: TDC2016SP - Trilha Programação Funcional

IO

main = do putStrLn "Qual é o seu nome?"

nome <- getLine

putStrLn ("Olá, " ++ nome ++ "!")

putStrLn :: String -> IO ()

getLine :: IO String

Page 45: TDC2016SP - Trilha Programação Funcional

Lista

do x <- [1, 2, 3]

y <- ['a', 'b']

Return (x, y)

[(1, 'a'), (2, 'b'), (3, 'c')]

[(x,y) | x <- [1,2,3], y <- ['a', 'b'])

.net LINQ

Page 46: TDC2016SP - Trilha Programação Funcional

Perguntas

[email protected]