MonadReader, Reader e ReaderT: Implementação e Propriedades em Haskell

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.

Tags: Haskell MonadReader Reader ReaderT Monad transformers

Publicado em 7-4 19:32