Como faço para criar um identificador na memória em Haskell?
Pergunta
Quero algo que se pareça com um identificador de arquivo, mas que seja realmente apoiado por um buffer na memória para usar para redirecionamentos de E/S.Como posso fazer isso?
Solução
Não é possível sem modificar o compilador.Isso ocorre porque Handle é um tipo de dados abstrato, não uma typeclass.
Outras dicas
Acabei de escrever uma biblioteca que fornece isso, chamada "knob" [invasão].Você pode usá-lo para criar Handle
s que fazem referência/modificam um 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 você puder expressar o que deseja fazer em termos de C ou chamadas de sistema, poderá usar a Foreign Function Interface (FFI) de Haskell.Comecei a sugerir o uso do mmap, mas pensando bem, acho que o mmap pode ser um mapeamento errado, mesmo se você o usar com a opção anônima.
Você pode encontrar mais informações sobre o Haskell FFI no wiki haskell.org.
Isto pode não ser possível. GHC, pelo menos, parece exigir um identificador para ter um descritor de arquivo do sistema operacional usado para todas as operações de leitura/gravação/busca.
Ver /libraries/base/IOBase.lhs
das fontes do GHC.
Você pode obter o mesmo efeito contando com a ajuda do sistema operacional:crie um arquivo temporário, conecte o identificador a ele e mapeie a memória do arquivo para os redirecionamentos de E/S.Dessa forma, toda a E/S do identificador ficaria visível na seção mapeada de memória.
Na verdade, isso é um bug no design da biblioteca e que também me incomodou.Vejo duas abordagens para fazer o que você deseja, mas nenhuma delas é muito atraente.
Crie uma nova typeclass, faça com que o identificador atual seja uma instância dela, escreva outra instância para fazer os dados na memória e altere todos os seus programas que precisam usar esse recurso.Possivelmente isso é tão simples quanto importar
System.SIO
(ou como você quiser chamá-lo) em vez deSystem.IO
.Mas se você usar rotinas de E/S personalizadas em bibliotecas comoData.ByteString
, há mais trabalho a ser feito lá.Reescreva as bibliotecas de E/S para estendê-las para suportar isso.Não é trivial e dá muito trabalho, mas não seria um trabalho particularmente difícil de fazer.No entanto, você tem um problema de compatibilidade com sistemas que não possuem esta biblioteca.
Para adicionar uma resposta moderna a esta pergunta, você poderia usar createPipe
de System.Process
:
createPipe :: IO (Handle, Handle)
https://www.stackage.org/haddock/lts-10.3/process-1.6.1.0/System-Process.html#v:createPipe