Sto cercando di ottenere una comprensione più profonda della pigrizia in Haskell.In che modo la pigrizia e l'I/O lavorano insieme in Haskell?
stavo immaginando il seguente frammento di oggi:
data Image = Image { name :: String, pixels :: String }
image :: String -> IO Image
image path = Image path <$> readFile path
L'appello è che si potrebbe semplicemente creare un'istanza immagine e passarlo in giro; se ho bisogno dei dati di immagine sarebbe letto pigramente - in caso contrario, il costo di tempo e la memoria di leggere il file potrebbe essere evitato:
main = do
image <- image "file"
putStrLn $ length $ pixels image
Ma è così che funziona in realtà? In che modo la pigrizia è compatibile con IO? Sarà letto il file di lettura indipendentemente dal fatto che acceda allo pixels image
o il runtime lascerà quel thunk non valutato se non mi riferisco mai ad esso?
Se l'immagine viene effettivamente letta pigramente, non è possibile che le azioni di I/O vengano eseguite in modo anomalo? Ad esempio, cosa succede se immediatamente dopo aver chiamato image
ho eliminato il file? Ora la chiamata putStrLn non troverà nulla quando tenta di leggere.
Grazie per questa risposta! In effetti, è stata la descrizione di HGetContents di RWH a confondermi su questo problema. Non mi ero reso conto che si trattava di un caso speciale e ho utilizzato sotto chiamate IO non sicure. Quindi, in pratica, il mio esempio legge il file non appena viene elaborata l'azione readFile? Sembra molto più coerente, se è così. – Bill
@Bill: Ecco l'implementazione per readFile, direttamente dalle librerie standard di GHC: 'readFile name = openFile name ReadMode >> = hGetContents' Quindi no, il tuo esempio rientra nella categoria" cheating cheater ". Detto questo, le funzioni di I/O pigro di solito sono abbastanza sicure per la maggior parte degli usi pratici quotidiani, quindi non si suda troppo a meno che la purezza non sia molto importante per te. –
So che Oleg dice che "UnsafeInterleaveIO" rompe la trasparenza referenziale, ma non sono d'accordo. Direi che è semplicemente non deterministico, come molte cose nella monade 'IO'. 'GetCurrentTime' interrompe la trasparenza referenziale perché posso usarlo per determinare quale delle due funzioni estrinsicamente uguali è implementata in modo più efficiente? –