Ответ 1
Это невозможно без изменения компилятора. Это происходит потому, что Handle является абстрактным типом данных, а не типом.
Я хочу что-то похожее на дескриптор файла, но на самом деле поддерживается буфером в памяти для использования для перенаправления ввода-вывода. Как я могу это сделать?
Это невозможно без изменения компилятора. Это происходит потому, что Handle является абстрактным типом данных, а не типом.
Я просто написал библиотеку, которая предоставляет это, называемую "ручкой" [hackage]. Вы можете использовать его для создания 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 вы можете найти на wiki haskell.org.
Это может быть невозможно. GHC, по крайней мере, кажется, требует, чтобы дескриптор имел дескриптор файла ОС, который используется для всех операций чтения/записи/поиска.
См. /libraries/base/IOBase.lhs
из источников GHC.
Вы можете получить тот же эффект, заручившись помощью операционной системы: создайте временный файл, подключите к нему дескриптор, а затем сохраните карту для перенаправления ввода-вывода. Таким образом, все дескрипторы ввода/вывода станут видимыми в области отображения памяти.
На самом деле это ошибка в дизайне библиотеки, и это меня тоже раздражало. Я вижу два подхода к тому, что вы хотите, ни один из которых ужасно привлекателен.
Создайте новый typeclass, сделайте текущий дескриптор экземпляром, напишите еще один экземпляр, чтобы сделать объект данных в памяти, и измените все ваши программы, которые должны использовать этот объект. Возможно, это так же просто, как импортировать 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