confusão Haskell com ContT, callCC, quando
-
19-09-2019 - |
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.
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.