O documento apresenta uma introdução às mônades em Haskell, discutindo sua definição abstrata, aplicações práticas e como elas permitem lidar com efeitos colaterais de forma pura através do uso de monóides na categoria de endofunctors.
Sobre o palestrante
EduardoSato
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
3.
Pesquisa
- Quem aquiprograma em Haskell?
- Quem aqui usa/conhece Mônades em Haskell ou outra linguagem?
- Palestra do Roberto "Haskell 101"
A falácia doTutorial 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!”
10.
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
11.
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?
12.
Mônades em programaçãofuncional
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!
13.
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
14.
Haskell: curso relâmpago
Assinatura
Definição
Chamadade 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
15.
Haskell: curso relâmpago
Descontstrução
dataMaybe 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"
16.
Motivação: um simplesavaliador:
Tema e variações
Tema: o avaliador básico
data Termo = Const Int | Div Termo Termo deriving (Show)
avaliar :: Termo -> Int
avaliar (Const n) = n
avaliar (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 expr
erro = avaliar divisaoPorZero
Div
Div Const
23Const
1932
Const
2
Div
Const
1
Const
0
Variação 1
Tratamento deErros
data Termo = Const Int | Div Termo Termo deriving (Show)
data M a = Valor a | Exc String deriving (Show)
avaliar :: Termo -> M Int
avaliar (Const n) = Valor n
avaliar (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)
Variação 2: prelúdio
Composiçãode 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)
21.
Variação 2
Estado: contaro 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 Int
avaliar (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
Variação 3
Saída: imprimirlog
data Termo = Const Int | Div Termo Termo deriving (Show)
data M a = Saida (String, a) deriving (Show)
avaliar :: Termo -> M Int
avaliar (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 -> String
imprimirLinha t a = show t ++ " = " ++ show a ++ "n"
Mônades: o quesã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
27.
Leis
- Identidade:
- returna >>= f = f a
- m >>= return = m
- Associatividade:
- (m >>= f) >>= g = m >>= (x -> f x >>= g)
28.
Tema revisitado
Mônade Identidade
dataTermo = 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 Int
avaliar (Const a) = return a
avaliar (Div t u) = avaliar t >>= a ->
avaliar u >>= b ->
return (a `div` b)
avaliar t >>= (a -> avaliar u >>= (b -> return (a `div` b)))
Variação 1 revistada
Exceções
dataTermo = 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 a
raise e = Raise e
31.
Variação 1 revistada
avaliar:: Termo -> Exception Int
avaliar (Const a) = return a
avaliar (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 expr
erro = avaliar divisaoPorZero
Variação 2 revistada
dataTermo = Const Int | Div Termo Termo deriving (Show)
data State a = State { runState :: (Int -> (a, Int)) }
instance Monad State where
return 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))
34.
Variação 2 revistada
avaliar:: Termo -> State Int
avaliar (Const a) = return a
avaliar (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
Variação 3 revistada
dataTermo = Const Int | Div Termo Termo deriving (Show)
data Writer a = Writer { runWriter :: (String, a) } deriving (Show)
instance Monad Writer where
return 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 -> String
imprimirLinha t a = show t ++ " = " ++ show a ++ "n"
37.
Variação 3 revistada
avaliar:: Termo -> Writer Int
avaliar (Const a) = output (imprimirLinha (Const a) a) >>= _ ->
return a
avaliar (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
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)))
40.
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)
41.
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)
42.
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)