Как создать дескриптор в памяти в Haskell?
Вопрос
Мне нужно что-то, что выглядит как дескриптор файла, но на самом деле поддерживается буфером в памяти, который можно использовать для перенаправления ввода-вывода.Как я могу это сделать?
Решение
Без модификации компилятора это невозможно.Это связано с тем, что Handle — это абстрактный тип данных, а не класс типов.
Другие советы
Я только что написал библиотеку, которая это обеспечивает, под названием «кноб» [хакерство].Вы можете использовать его для создания Handle
которые ссылаются/изменяют 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)
Если вы можете выразить то, что хотите сделать, с помощью C или системных вызовов, вы можете использовать интерфейс внешних функций Haskell (FFI).Я начал предлагать использовать mmap, но, поразмыслив, думаю, что mmap может быть неправильным сопоставлением, даже если вы использовали его с анонимной опцией.
Дополнительную информацию о Haskell FFI можно найти на вики haskell.org.
Это может быть невозможно. ГХК, по крайней мере, похоже, требуется, чтобы дескриптор имел дескриптор файла ОС, который используется для всех операций чтения/записи/поиска.
Видеть /libraries/base/IOBase.lhs
из источников GHC.
Вы можете получить тот же эффект, воспользовавшись помощью ОС:создайте временный файл, подключите к нему дескриптор, а затем сопоставьте файл с памятью для перенаправления ввода-вывода.Таким образом, все дескрипторы ввода-вывода станут видимыми в разделе, отображаемом в памяти.
На самом деле это ошибка в дизайне библиотеки, и она меня тоже раздражает.Я вижу два подхода к тому, чтобы делать то, что хочешь, и ни один из них не является особенно привлекательным.
Создайте новый класс типов, сделайте текущий дескриптор его экземпляром, напишите еще один экземпляр для обработки данных в памяти и измените все свои программы, которым необходимо использовать эту возможность.Возможно, это так же просто, как импортировать
System.SIO
(или как вы это называете) вместоSystem.IO
.Но если вы используете собственные процедуры ввода-вывода в таких библиотеках, какData.ByteString
, там еще есть над чем поработать.Перепишите библиотеки ввода-вывода, чтобы расширить их поддержку.Это нетривиально и требует много работы, но это не будет особенно сложной работой.Однако тогда у вас возникнет проблема совместимости с системами, в которых нет этой библиотеки.
Чтобы добавить современный ответ на этот вопрос, вы можете использовать createPipe
от System.Process
:
createPipe :: IO (Handle, Handle)
https://www.stackage.org/haddock/lts-10.3/process-1.6.1.0/System-Process.html#v:createPipe