1801


AとBという2つのストリームがあった場合、Aのストリームを読み込み、処理を加え、Bのストリームに結果を受け流すような処理はどのように書くのでしょうか。

一旦Aのストリームの内容を書き出して処理を加え、その結果でBのストリームを作る、というような方法しかないのでしょうか。


CC BY-SA 3.0
2014-12-16T09:11:44.663
1724
2014-12-18T05:44:32.667
3510
question
common-lisp
UNIXのパイプ処理のようにストリームを扱いたい


> 一旦Aのストリームの内容を書き出して処理を加え、その結果でBのストリームを作る、というような方法しかないのでしょうか。

理想的には

[code]

    (defun f (in out) (loop (write-char (read-char in) out)))
    (defun g (in out) (loop (write-char (read-char in) out)))
    (let ((in ...) (out ...) (pipe ...))
      (make-thread (lambda () (f in pipe))
      (make-thread (lambda () (g pipe out)))
    
[/code]

と書きたいのですよね。しかし、`(pipe ...)` に相当するものが無いので、CLの範疇では

[code]

    (defun read-all (in) ...)
    (defun f (in) (make-next-input-stream (dosomething (read-all in)))))
    (defun g (in) (make-next-input-stream (dosomething (read-all in)))))
    (let ((in ...))
      (read-all (g (f in))))
    
[/code]

とするしか無く、本当のパイプとは似ていない形になってしまいます。いくつか方法が考えられます。

  1. clで`(pipe ...)`を実装してしまうこと。しかし、streamクラスはbuilt-in-typeなので継承できません。NG. 追記: gray-streamで拡張できるようです。 <http://kurohuku.blogspot.jp/2009/11/gray-stream.html> ここの make-virtual-stream は実質pipeですね。

  2. iolibを使う。`(iolib.syscalls:pipe)`はあるのですが、帰ってくるのがFile Descriptor番号なので、いかんせん使いにくい。ラッパがあればいいのですが、ないようです。そこで`mkfifo`を使いましょう。

たとえば以下のような感じ。

[code]

    (unwind-protect
      (let ((fifo "/tmp/myfifo")
            (in ...) (out ...))
        (iolib.syscalls:MKFIFO fifo 255)
        (with-open-file (fifoin fifo :direction :input)
          (with-open-file (fifoout fifo :direction :output)
            (make-thread (lambda () (f in fifoout))
            (make-thread (lambda () (g fifoin out))))))
     (delete-file fifo))
    
[/code]

たぶんうまく行くはず。

  3. sbclなら `sb-unix:unix-pipe` が返してきたFD番号を `SB-SYS:make-fd-stream` でストリームに出来ます。これもユーティリティーがあればいいのに。あと、生成したpipeを消す方法がわからないのですが大丈夫なのか不明です。

例:

[code]

    (multiple-value-bind (read-fd write-fd) (sb-unix:unix-pipe)
      (let ((pipeout (SB-SYS:make-fd-stream write-fd :output t))
            (pipein  (SB-SYS:make-fd-stream read-fd  :input  t)))
         ...))
    
[/code]

iolibがもっとしっかり使いやすくなっていればいいのですけどね。 pipe系の問題としては、lispオブジェクトを渡せないということでしょうか。
charしか流せません。

  4. cl-asyncとかどうなってるんでしょうね。なにか出来そうな気がしますが、知りません。


CC BY-SA 3.0
2014-12-16T16:26:23.180
1801
2014-12-18T05:44:32.667
2014-12-18T05:44:32.667
4051
4051
1724
answer