Digite o erro ao tentar implementar a função (>> =) para criar um transformador de Monad personalizado

StackOverflow https://stackoverflow.com/questions/2661895

Pergunta

Estou tentando criar um transformador de Monad para um projeto futuro, mas, infelizmente, minha implementação da função da Monad Typeclasse (>> = =) não funciona.

Primeiro de tudo, aqui está a implementação da Mônada subjacente:

newtype Runtime a = R { 
  unR :: State EInfo a
} deriving (Monad)

Aqui, a implementação do TypeClasse da Mônada é feita automaticamente pelo GHC (usando o GeneralizedNewtypeDeriving idioma Pragma). O transformador da Mônada é definido como assim:

newtype RuntimeT m a = RuntimeT {
  runRuntimeT :: m (Runtime a)
} 

O problema vem da maneira como eu instanculo a função (>> =) do Monad TypeClasse:

instance (Monad m) => Monad (RuntimeT m) where
    return a = RuntimeT $ (return . return) a
    x >>= f =  runRuntimeT x >>= id >>= f

Do jeito que eu vejo, o primeiro >>= corre no subjacente m Mônada. Desta forma, runRuntimeT x >>= Retorna um valor do tipo Runtime a (certo ?). Então, o seguinte código, id >>=, deve retornar um valor do tipo a. Este valor é transmitido para a função f do tipo f :: (Monad m) => a -> RuntimeT m b.

E aqui vem o problema do tipo: o f O tipo da função não corresponde ao tipo exigido pela função (>> =). Jow posso fazer disso coerente? Eu posso ver por que isso não funciona, mas não consigo transformá -lo em algo funcional.

Editar: a mensagem de erro:

Core.hs:34:4:
    Occurs check: cannot construct the infinite type: m = RuntimeT m
    When generalising the type(s) for `>>='
    In the instance declaration for `Monad (RuntimeT m)'
Failed, modules loaded: none.

Obrigado pela ajuda e não hesite em corrigir nenhuma falha na minha mensagem,
Charlie P.

Foi útil?

Solução

Para seguir o que Reid Barton disse sobre StateT - Veja como você definiria RuntimeT usando StateT. o Runtime Monad pode então ser definido trivialmente usando a Mônada de Identidade.

newtype RuntimeT m a = R { 
  unR :: StateT EInfo m a
}

type Runtime = RuntimeT Identity

instance Monad m => Monad (RuntimeT m) where
    return = R . return

    (R m) >>= f = R (m >>= unR . f)

Outras dicas

O habitual StateT s m Monad envia a para s -> m (a, s) Mas você está trabalhando com m (s -> (a, s)) em vez de. Eu não acho que o último forma uma mônada para o general s. Tem certeza que não quer apenas usar StateT?


Eis porque eu não acho am (s -> (a, s)) é uma mônada: escrever >>= Eu preciso de uma função que tome argumentos de tipos

m (s -> (a, s))
a -> m (s -> (b, s))

e retorna um valor do tipo

m (s -> (b, s))

Os "efeitos" (ou seja, fmap (const ())) do resultado deve ser o do primeiro argumento, já que não temos como obter um a passar para o segundo argumento. Desde m aparece apenas na parte externa do tipo de resultado, não podemos usar o segundo argumento para nada - não haverá como nos livrar do m Introduz.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top