Pregunta

Continuando búsqueda de hacer sentido de ContT y amigos. Por favor, considere el código (absurdo pero ilustrativo) a continuación:

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 no compila. Sin embargo, si el reemplazar el when con la llamada k comentado por debajo de ella, que se compila. ¿Qué está pasando?

Por otra parte, si yo comente la línea x2, también compila. ???

Obviamente, esta es una versión destilada del código original y así todos los elementos tienen un propósito. Apreciar ayuda explicativa sobre lo que está pasando y cómo solucionarlo. Gracias.

¿Fue útil?

Solución

El problema en este caso tiene que ver con los tipos de when y either, no algo en particular a ContT:

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

El segundo argumento tiene que ser de tipo m () por alguna m mónada. La línea when de su código de este modo se podría modificar de esta manera:

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

para hacer la compilación de código. Esto probablemente no es lo que quiere hacer, pero nos da una pista sobre lo que podría estar equivocado:. Tipo de k se ha inferido a ser algo desagradable para when

Ahora, para la firma either: Observe que los dos argumentos a either deben ser funciones que producen resultados del mismo tipo. El tipo de return aquí está determinada por el tipo de x, que a su vez está fijado por la firma explícita sobre v. Por lo tanto el bit (k . Left) debe tener el mismo tipo; esto a su vez fija el tipo de k al (GHC-determinado)

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

Esto es incompatible con las expectativas de when.

Al comentar la línea x2, sin embargo, se elimina su efecto en vista del tipo de corrector del código, por lo k ya no es forzado en un tipo de inconveniente y es libre de asumir el tipo

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

que está muy bien en el libro de when. De este modo, el código se compila.

Como nota final, he utilizado las instalaciones de puntos de ruptura GHCi para obtener el tipo exacto de k bajo los dos escenarios - Estoy muy lejos de expertos suficiente para escribirlas a mano y de ninguna manera seguros de su corrección. :-) Use :break ModuleName line-number column-number a probarlo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top