Upload
tdc-globalcode
View
133
Download
1
Embed Size (px)
Citation preview
Desvendando os mistérios das MônadesAprenda a domar os efeitos colaterais com Mônades em Haskell
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
Pesquisa
- Quem aqui programa em Haskell?- Quem aqui usa/conhece Mônades em Haskell ou outra linguagem?- Palestra do Roberto "Haskell 101"
Quantidade de tutorias de Mônades
https://wiki.haskell.org/Monad_tutorials_timeline
A falácia do Tutorial de Mônades
Mônades?
Mônade: definição
Uma mônade nada mais é que: “um monóide na categoria dos endofunctores”
Problem?
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!”
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
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?
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!
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
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
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"
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
Tema: resultado
ghci> resposta
42
ghci> erro
*** Exception: divide by zero Ops!
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)
Resultado
ghci> resposta
Valor 42
ghci> erro
Exc "divisao por zero"
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)
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
Resultado
ghci> resposta
(42,2)
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"
Variação 3 - Cont.
expr = Div (Div (Const 1932) (Const 2)) (Const 23)
Saida (saida, resposta) = avaliar expr
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
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
Leis
- Identidade:- return a >>= f = f a
- m >>= return = m
- Associatividade:- (m >>= f) >>= g = m >>= (\x -> f x >>= g)
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)))
Tema revisitado
expr = Div (Div (Const 1932) (Const 2)) (Const 23)
resposta = avaliar expr
ghci> resposta
Identity 42
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
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
Resultado
ghci> resposta
Return 42
ghci> erro
Raise "divisao por zero"
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))
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
Resultado
ghci> resposta
(42,2)
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"
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
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
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)))
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)
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)
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)
Outras Mônades
- Par: paralelismo- Lista: não determinismo- Cont: continuações- Parsec: parsers- IO- Lógica- Probabilidade- Free Monads -> DSLs- etc
IO
main = do putStrLn "Qual é o seu nome?"
nome <- getLine
putStrLn ("Olá, " ++ nome ++ "!")
putStrLn :: String -> IO ()
getLine :: IO String
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
Perguntas