Haskell でメモリ内ハンドルを作成するにはどうすればよいですか?
質問
ファイルハンドルのように見えますが、実際には I/O リダイレクトに使用するメモリ内バッファーによってバックアップされているものが必要です。これどうやってするの?
解決
コンパイラを変更しないと不可能です。これは、Handle が型クラスではなく抽象データ型であるためです。
他のヒント
私はこれを提供する「knob」というライブラリを作成しました [ハッキング]。それを使用して作成できます Handle
を参照/変更する s 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 wiki を参照してください。
これは不可能かもしれません。 GHC, 、少なくとも、すべての読み取り/書き込み/シーク操作に使用される OS ファイル記述子を持つハンドルが必要なようです。
見る /libraries/base/IOBase.lhs
GHC情報源より。
OS の助けを借りれば、同じ効果が得られる場合があります。一時ファイルを作成し、そのファイルにハンドルを接続して、I/O リダイレクト用にファイルをメモリ マップします。こうすることで、すべてのハンドル I/O がメモリ マップされたセクションに表示されるようになります。
これは実際にはライブラリ設計のバグであり、私もイライラさせられます。やりたいことを実現するには 2 つのアプローチがあると思いますが、どちらもそれほど魅力的ではありません。
新しいタイプクラスを作成し、現在のハンドルをそのインスタンスにし、メモリ内データの処理を行う別のインスタンスを作成し、この機能を使用する必要があるプログラムをすべて変更します。おそらくこれはインポートと同じくらい簡単です
System.SIO
(またはあなたがそれを呼びたいものは何でも)の代わりにSystem.IO
. 。ただし、次のようなライブラリでカスタム I/O ルーチンを使用すると、Data.ByteString
, 、そこにはやるべきことがまだあります。I/O ライブラリを書き換えて、これをサポートするように拡張します。簡単なことではなく、多くの作業が必要ですが、特に難しい作業ではありません。ただし、このライブラリを持たないシステムとの互換性の問題が発生します。
この質問に現代的な答えを追加するには、次のようにします。 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