Come posso creare un handle in memoria in Haskell?
Domanda
Voglio qualcosa che assomigli a un handle di file ma che sia in realtà supportato da un buffer in memoria da utilizzare per i reindirizzamenti I/O.Come posso fare questo?
Soluzione
Non è possibile senza modificare il compilatore.Questo perché Handle è un tipo di dati astratto, non una classe di tipi.
Altri suggerimenti
Ho appena scritto una libreria che fornisce questo, chiamata "knob" [hacking].Puoi usarlo per creare Handle
s che fanno riferimento/modifica a ByteString
:
import Data.ByteString (pack)
import Data.Knob
import System.IO
main = do
knob <- newKnob (pack [])
h <- newFileHandle knob "test.txt" WriteMode
hPutStrLn h "Hello world!"
hClose h
bytes <- Data.Knob.getContents knob
putStrLn ("Wrote bytes: " ++ show bytes)
Se riesci a esprimere ciò che vuoi fare in termini di C o chiamate di sistema, potresti utilizzare la Foreign Function Interface (FFI) di Haskell.Ho iniziato a suggerire di utilizzare mmap, ma ripensandoci penso che mmap potrebbe essere una mappatura nel modo sbagliato anche se la usi con l'opzione anonima.
Puoi trovare ulteriori informazioni sulla FFI Haskell sul wiki haskell.org.
Questo potrebbe non essere possibile. GHC, almeno, sembra richiedere un handle per avere un descrittore di file del sistema operativo utilizzato per tutte le operazioni di lettura/scrittura/ricerca.
Vedere /libraries/base/IOBase.lhs
dalle fonti GHC.
Potresti riuscire a ottenere lo stesso effetto avvalendoti dell'aiuto del sistema operativo:creare un file temporaneo, collegarvi l'handle e quindi mappare in memoria il file per i reindirizzamenti I/O.In questo modo, tutti gli I/O dell'handle diventerebbero visibili nella sezione mappata in memoria.
In realtà si tratta di un bug nella progettazione della libreria e che ha infastidito anche me.Vedo due approcci per fare ciò che vuoi, nessuno dei quali è terribilmente attraente.
Crea una nuova classe di tipo, rendi l'handle corrente un'istanza di essa, scrivi un'altra istanza per eseguire i dati in memoria e modifica tutti i tuoi programmi che devono utilizzare questa funzionalità.Forse questo è semplice come importare
System.SIO
(o come vuoi chiamarlo) invece diSystem.IO
.Ma se usi le routine I/O personalizzate in librerie comeData.ByteString
, c'è ancora molto lavoro da fare lì.Riscrivere le librerie I/O per estenderle per supportare questo.Non banale e richiede molto lavoro, ma non sarebbe un lavoro particolarmente difficile da svolgere.Tuttavia, hai un problema di compatibilità con i sistemi che non dispongono di questa libreria.
Per aggiungere una risposta moderna a questa domanda, potresti usare createPipe
da System.Process
:
createPipe :: IO (Handle, Handle)
https://www.stackage.org/haddock/lts-10.3/process-1.6.1.0/System-Process.html#v:createPipe