Classe de Tipos MonadReader
-- Definição reescrita com nomes alternativos
class Monad m => MonadReader r m | m -> r where
perguntar :: m r
perguntar = leitor id
local :: (r -> r) -> m a -> m a
leitor :: (r -> a) -> m a
leitor f = do
r <- perguntar
return (f r)
instance Monad m => MonadReader r (ReaderT r m) where
perguntar = ReaderT.perguntar
local = ReaderT.local
leitor = ReaderT.leitor
solicitar :: MonadReader r m => (r -> a) -> m a
solicitar = leitor
A classe MonadReader fornece uma interface unificada para monads que suportam acesso a um ambiente compartilhado, como ReaderT e RWST. Ela inclui três operações principais: perguntar para obter o valor do ambiente, local para modificar temporariamente o ambiente dentro de uma computação, e leitor para aplicar uma função ao ambiente. A função solicitar é um sinônimo para leitor.
Transformador Monad ReaderT
-- Definição alternativa do ReaderT
newtype ReaderT r m a = ReaderT { executarReaderT :: r -> m a }
instance (Monad m) => Monad (ReaderT r m) where
return = elevar . return
m >>= k = ReaderT $ \ r -> do
a <- executarReaderT m r
executarReaderT (k a) r
instance MonadTrans (ReaderT r) where
elevar = elevarReaderT
elevarReaderT :: m a -> ReaderT r m a
elevarReaderT m = ReaderT (const m)
O ReaderT é um transformador monad que encapsula uma computação dependente de um ambiente r. Seu tipo newtype envolve uma função r -> m a. A instância Monad para ReaderT segue as leis monádicas, com return elevando valores do monad interno e bind propagando o ambiente. A operação elevar permite integrar computações do monad base m.
-- Prova das leis monádicas para ReaderT (versão resumida)
-- 1. return a >>= f ≡ f a
-- 2. m >>= return ≡ m
-- 3. (m >>= f) >>= g ≡ m >>= (\x -> f x >>= g)
Funções do Transformaodr ReaderT
perguntar :: (Monad m) => ReaderT r m r
perguntar = ReaderT return
local :: (Monad m) => (r -> r) -> ReaderT r m a -> ReaderT r m a
local = comReaderT
leitor :: (Monad m) => (r -> a) -> ReaderT r m a
leitor f = ReaderT (return . f)
solicitar :: (Monad m) => (r -> a) -> ReaderT r m a
solicitar f = ReaderT (return . f)
mapearReaderT :: (m a -> n b) -> ReaderT r m a -> ReaderT r n b
mapearReaderT f m = ReaderT $ f . executarReaderT m
comReaderT :: (r' -> r) -> ReaderT r m a -> ReaderT r' m a
comReaderT f m = ReaderT $ executarReaderT m . f
A função comReaderT permite alterar o tipo do ambiente aplicando uma transformação, enquanto local é um caso especial que mantém o mesmo tipo. As demais funções fornecem operações utilitárias para manipular o contexto do ReaderT.
Monad Reader
type Reader r = ReaderT r Identidade
executarReader :: Reader r a -> r -> a
executarReader m = executarIdentidade . executarReaderT m
mapearReader :: (a -> b) -> Reader r a -> Reader r b
mapearReader f = mapearReaderT (Identidade . f . executarIdentidade)
comReader :: (r' -> r) -> Reader r a -> Reader r' a
comReader = comReaderT
O monad Reader é uma especialização do ReaderT usando o monad Identidade como base, simplificando o uso quando não há efeitos adicionais além do acesso ao ambiente.
Exemplo de Aplicação
import Control.Monad.Reader
saudacao :: Reader String String
saudacao = do
nome <- perguntar
return ("olá, " ++ nome ++ "!")
despedida :: Reader String String
despedida = solicitar $ \nome -> ("adeus, " ++ nome ++ "!")
conversa :: Reader String String
conversa = solicitar (const (++)) <*> saudacao <*> despedida
principal :: IO ()
principal = print . executarReader conversa $ "Maria"
Neste exemplo, as funções saudacao e despedida utilizam o monad Reader para acessar uma string de ambiente, enquanto combina operações usando aplicativos. O monad Reader permite compartilhar dados de configuração sem passá-los explicitamente.