Domanda

Continuando tentativo di dare un senso a ContT e amici. Si prega di prendere in considerazione il codice (assurdo ma illustrativo) di seguito:

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

Questo codice non viene compilato. Tuttavia, se la sostituzione del when con la chiamata k commentata sotto di esso, si compila. Cosa sta succedendo?

In alternativa, se io commento la linea x2, si compila anche. ???

Ovviamente, questa è una versione distillata del codice originale e quindi tutti gli elementi hanno uno scopo. Apprezzare aiuto esplicativo su quello che sta succedendo e come risolvere il problema. Grazie.

È stato utile?

Soluzione

Il problema qui ha a che fare con i tipi di when e either, senza niente di particolare a ContT:

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

Il secondo argomento deve essere di tipo m () per qualche monad m. La linea when del codice potrebbe quindi essere modificato in questo modo:

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

per rendere il codice di compilazione. Questo non è probabilmente quello che si vuole fare, ma ci dà un suggerimento di quello che potrebbe essere sbagliato:. Tipo di k è stato dedotto di essere qualcosa di sgradevole per when

Ora, per la firma either: notare che i due argomenti di either devono essere funzioni che producono risultati dello stesso tipo. Il tipo di return qui è determinato dal tipo di x, che è a sua volta fissato dalla firma esplicito su v. Così il bit (k . Left) deve avere lo stesso tipo; questo a sua volta fissa il tipo di k a (GHC-determinato)

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

Ciò è incompatibile con le aspettative di when.

Quando commentare la linea x2, tuttavia, il suo effetto sulla vista del tipo di controllo del codice viene rimosso, in modo k non è più costretto in un tipo scomodo ed è libero di assumere il tipo

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

che va bene nel libro di when. Così, il codice viene compilato.

Come nota finale, ho usato i punti di interruzione di impianto GHCi per ottenere l'esatto tipo di k sotto le due scenari - Sono neanche lontanamente esperto abbastanza per scriverle a mano e di essere in alcun modo garantita la loro correttezza. :-) Utilizzare :break ModuleName line-number column-number di provarlo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top