Gauche > Archives > 2012/06/27

2012/06/27 02:35:59 UTCとおる。
#
http://perldoc.perl.org/perlop.html#I%2fO-Operators SED や AWK をよく知らない人には混乱の元でしかないような気がしなくもないです。
#
The null filehandle <> is special: it can be used to emulate the behavior of sed and awk, and any other Unix filter program that takes a list of filenames, doing the same to each line of input from all of them. Input from <> comes either from standard input, or from each file listed on the command line. Here's how it works: the first time <> is evaluated, the @ARGV array is checked, and if it is empty, $ARGV[0] is set to "-", which when opened gives you standard input. The @ARGV array is then processed as a list of filenames.
2012/06/27 03:12:30 UTCyamasushi
#
ダイヤモンド演算子を一般化すると、与えられたリストが空なら標準入力ポート、空でないなら各ファイルごとにポートをオープン、して与えられた手続きに渡していく、みたいな感じなのかなあと思いました。マニュアルのスクリプト例「grep」の一般化のようなイメージです。
#
リストでなくポートをあたえると、そのポートを処理するようにすればダイヤモンド演算子っぽくなりますね。
2012/06/27 04:37:07 UTCshiro
#
私がここの議論でイメージしてたのはこんな感じ
#
(define command-line (make-parameter '())) ;; r7rs

;; 名前は要検討
(define (input-files->generator reader
                                :optional (files (let1 fs (command-line)
                                                   (if (pair? fs)
                                                     (cdr fs)
                                                     '()))))
  (if (null? files)
    (cute reader (current-input-port))
    (gconcatenate (map (cut file->generator <> reader) fs))))
#
確かに、ファイルリストが()の時に標準入力から読むっていうのはちょっとイレギュラーで気持ち悪いんだけど、unixのコマンドはそういう動作をするものが多いから、そういうモデルだってことがわかればいいんじゃないかな。
#
あ、でも"-"を特別扱いする必要もあるのか。そしたらもっとコマンドライン処理っぽい名前にした方がいいか。
2012/06/27 06:49:34 UTCyamasushi
#
generatorにしてしまうとファイル名の情報が消えてしまうので、portを列挙するような形のほうが一般なのかなあと思ったのでした。
#
(gauche.parameterについては今知りました。(汗)
2012/06/27 06:54:33 UTCshiro
#
んー、何に使いたいかによるんじゃないですかね。Perlで<>使うときって、個々の入力ファイル名を気にしましたっけ? まあ、(1)コマンドラインに列挙されたファイルか標準入力からportを次々に返すジェネレータ (2)portのジェネレータを取って各行などを返すジェネレータを作るコンバータ、を揃えておけばどちらでもできますね。
2012/06/27 07:10:22 UTCyamasushi
#
マニュアルの「Schemeスクリプトを書く」のサンプルがどのように書き換えられるだろうかと考えていました。
2012/06/27 07:22:01 UTCshiro
#
catとgrepで「見ている入力の粒度」が違うので、それぞれの粒度に対応した別々の表現があって良いでしょうね。catなら全部最初にくっつけてジェネレータで良いでしょうし、grepはあくまで入力ソースひとつづつ見る動作なので「入力ソースそれぞれ」と「各ソースにおける各行」との2重ループになる。
2012/06/27 08:36:07 UTCとおる。
#
http://perldoc.perl.org/perlvar.html#Variables-related-to-filehandles 個々の入力ファイル名とか今何行目を処理しているかとかも一応取得できるみたいですね。この辺はちょっと黒魔術っぽい感じなのであまり近寄らないようにしてるんですが(笑)。
2012/06/27 08:41:29 UTCshiro
#
そっかー。ジェネレータはそういうメタデータがいらない抽象世界の操作なんで、そういうものが欲しければポートの層でやるのが良さそう。とすると「指定したファイル/ポートを次々に読んでゆくポートを返す」port-concatenateみたいなのがあると良い? そのポートのメタデータとして低レベルの色々が取れるようにしておく。
#
ポートのメタデータの扱いは拡張しようと考えてる。(call-with-input-uri "http://example.com" (^p ...)) みたいなのを書く場合でも、渡されるポートpのメタデータとしてhttpレスポンスのヘッダ情報とかを取れると便利だし。Rubyのopen-uriは確かそんなふうになってたような。
2012/06/27 08:46:50 UTCとおる。
#
ファイル名とかのメタデータって、正常な動作をしているときは必要なくても、入力ファイルにエラーがあるときにエラーメッセージを出したりするときに便利なんですよね。
2012/06/27 08:55:46 UTCshiro
#
うむ。ただ、ポートから直接読んでる時はそれでいいんだけど、ポート→加工→加工→加工 みたいにパイプラインでデータを流してて下流でエラーになったときにどうするかってのはまだうまく解決できてない。流してゆくデータにこっそりメタデータをくっつけとくってのが定石だけど、(1)使わないときにはコード上で全く意識しないで良い (2)使わなければ性能のオーバヘッドもない (3)大抵の形のデータに使える、っていう3拍子揃ったうまい方法がなかなか。(Gaucheのコンパイラはextended pairの黒魔術を使ってソース情報のメタデータをS式に受け渡してるけど、これは(1)○(2)△(3)×。モナドをうまく使えば(3)は解決できるかもしれないけど(2)が厳しくなる。