Un titolo confuso per una domanda confusa! Capisco a) monade, b) la monade IO, c) il monito (Control.Monad.Cont), e d) il monad di trasformatore di continuazione ContT. (E capisco vagamente i trasformatori di Monade in generale - sebbene non sia abbastanza per rispondere a questa domanda.) Capisco come scrivere un programma dove all le funzioni sono in Cont monad (Cont r a
), e capisco come scrivere un programma dove all le funzioni sono contenute nella monade Cont/IO combinata (ContT r IO a
).Escaping dalla monade IO all'interno della monade Continuazione
Ma mi chiedo come potrei scrivere un programma in cui alcune funzioni sono in una monade combinato Cont/IO (ContT r IO a
) e altre funzioni sono solo in monade Cont (Cont r a
). Fondamentalmente, voglio scrivere l'intero programma in uno stile di continuazione, ma uso solo la monade IO dove necessario (molto simile al codice Haskell "normale", uso solo la monade IO dove necessario).
Per esempio prendere in considerazione queste due funzioni, in stile non-continuazione:
foo :: Int -> IO Int
foo n = do
let x = n + 1
print x
return $ bar x
bar :: Int -> Int
bar m = m * 2
Nota che foo
richiede IO ma bar
è puro. Ora ho capito come scrivere questo codice completamente utilizzando la monade di continuazione, ma avevo bisogno di infilare IO attraverso bar
così:
foo :: Int -> ContT r IO Int
foo n = do
let x = n + 1
liftIO $ print x
bar x
bar :: Int -> ContT r IO Int
bar m = return $ m * 2
ho faccio vogliono tutto il mio codice in stile continuazione, ma io don' t desidera utilizzare la monade IO su funzioni che non lo richiedono. Fondamentalmente, io piacerebbe definire bar
in questo modo:
bar :: Int -> Cont r Int
bar m = return $ m * 2
Purtroppo, non riesco a trovare un modo per chiamare una funzione Cont r a
monade (bar
) dall'interno di una funzione ContT r IO a
monade (foo
). C'è un modo per "sollevare" una monade non trasformata in una trasformata? Ad esempio, come posso modificare la linea "bar x
" in foo
in modo che possa chiamare correttamente bar :: Int -> Cont r Int
?
Grazie. Che funzioni. Ho anche trovato la mia soluzione, che mi ha dato esattamente quello che volevo (non ho dovuto cambiare 'Bar'):' liftCont :: Cont (m r) a -> ContT r m a'; 'liftCont c = ContT $ runCont c'. La mia soluzione scompatta il 'Cont' e costruisce un' ContT'. Penso che la tua soluzione sia migliore perché è polimorfica e non richiede una reale manipolazione delle strutture dati, quindi spunta per te. Ma posterò il mio come un'altra risposta, poiché è utile nel caso in cui non si possa modificare 'bar'. Anche +1 per la spiegazione del motivo per cui sarebbe impossibile usare IO in 'bar'. – mgiuca