Pergunta

Continuando busca de fazer sentido de ContT e amigos. Por favor, considere o código (absurdo, mas ilustrativa) abaixo:

v :: IO (Either String [String])
v = return $ Left "Error message"

doit :: IO (Either String ())
doit = (flip runContT return) $ callCC $ \k -> do
    x <- liftIO $ v
    x2 <- either (k . Left) return x
    when True $ k (Left "Error message 2")
    -- k (Left "Error message 3")
    return $ Right () -- success

Este código não compila. No entanto, se a substituir o when com a chamada k comentou abaixo dele, ele compila. O que está acontecendo?

Como alternativa, se eu comente a linha x2, também compila. ???

Obviamente, esta é uma versão destilada do código original e assim todos os elementos servem a um propósito. Apreciamos a ajuda de esclarecimento sobre o que está acontecendo e como corrigi-lo. Obrigado.

Foi útil?

Solução

O problema aqui tem a ver com os tipos de when e either, não nada de especial para ContT:

when :: forall (m :: * -> *). (Monad m) => Bool -> m () -> m ()
either :: forall a c b. (a -> c) -> (b -> c) -> Either a b -> c

O segundo necessidades argumento para ser do tipo m () por algum m mônada. A linha de when do seu código poderia, assim, ser alterado assim:

when True $ k (Left "Error message 2") >> return ()

para fazer a compilação de código. Esta não é provavelmente o que você quer fazer, mas nos dá uma dica sobre o que pode estar errado:. Tipo de k foi inferida a ser algo desagradável para when

Agora, para a assinatura either: aviso de que os dois argumentos para either deve ser funções que produzem resultados do mesmo tipo. O tipo de return aqui é determinada pelo tipo de x, que por sua vez é fixado pela assinatura explícita sobre v. Assim, o bit (k . Left) deve ter o mesmo tipo; isso em correções de volta o tipo de k em (GHC-determinado)

k :: Either String () -> ContT (Either String ()) IO [String]

Esta é incompatível com as expectativas da when.

Quando você comentar a linha x2, no entanto, o seu efeito sobre a visão do verificador de tipos do código é removido, então k não é forçado em um tipo de inconveniente e é livre para assumir o tipo

k :: Either [Char] () -> ContT (Either [Char] ()) IO ()

o que é bom no livro de when. Assim, as compilações de código.

Como nota final, eu usei instalação de pontos de interrupção de GHCi para obter os tipos exatos de k sob os dois cenários - Estou longe de ser suficiente especialista para escrevê-los à mão e ser de qualquer forma a certeza de sua exatidão. :-) Use :break ModuleName line-number column-number para testá-lo.

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