プレイスホルダ

さて、先日書いた pattern-match-lambda について。

少し改良してアンダーバーをプレイスホルダとして使えるようにした。

(define example
  (pattern-match-lambda ()
    ((_) 'arity1)
    ((_ _) 'arity2)
    ((_ _ _) 'arity3)))

(example 1 1 1) ;; ⇒ arity3

プレイスホルダの箇所はそこに何か有りさえすれば内容にかかわらずマッチし、マッチした内容を見ることも出来ない。 適当なパターン変数を書いてもよいのだが使わないということを明示できるし、無駄な比較処理などが入らないので効率もよい。 (コンパイラが充分に賢いなら差はなくなるはずだが。)

もしリテラル節にアンダーバーを記述した場合にはリテラルとしてマッチするようになり、プレイスホルダとしての機能は失われる。

(define example4
  (pattern-match-lambda (_)
    ((_) 'underbar)
    ((x) x)))

(example4 '_) ;; ⇒ underbar
(example4 'foo) ;; ⇒ foo

この挙動は R7RS の syntax-rules を真似したものだ。

これを機にあらためて syntax-rules におけるアンダーバーの扱いを見ると R5RS, R6RS, R7RS でそれぞれ異っていることに気付いた。 表にまとめてみよう。

R5RS R6RS R7RS
プレイスホルダとして使える ×
リテラル節に書いてよい ×

地味な違いだが、地味なだけに意識されにくい。 pattern-match-lambda の今回の改良にあたってこれが原因で R6RS では使えなくなってしまった。 syntax-rules だけを使っていれば移植性の高いものを書けると思っていたのに、そう簡単な話でもないようだ。

Document ID: 735c6332198a48e5ea92f4977463f856

sort と uniq で出来ること

動画ホスティングサイトから条件に合うものを丸ごとダウンロードしたいということがある。

適当なスクリプトでまず対象を絞り込んで動画 ID のリストを list.txt というファイル名で作成したらこんな感じだったとしよう。

ID001
ID002
ID003
ID004
ID005

そして実際にダウンロードするが、何らかの事情で三個目で中断した。

このときファイル名は「ID」「タイトル」「拡張子」から成るものとする。 ダウンロード済みのファイル名リストを作るのは簡単だ。 ls コマンドを使えばいい。

$ ls *.mp4 *.flv
ID001 ぬこパンチ.mp4
ID002 雪の日のぬこ.flv
ID003 俺のぬこがこんなに可愛いわけがない.mp4

では、まだダウンロードしていない動画のリストを作るにはどうすればよいだろうか。

ダウンロード済みのリストと list.txt とをくっつけて一度しか出現しないものを抜き出せばよいのである。

$ ls *.mp4 *.flv |gawk '{print $1;}' |cat - list.txt |sort |uniq -u >todo.txt
$ cat todo.txt
ID004
ID005

これで万事解決というわけではない。 ダウンロードしている間にも動画ホスティングサービスにはどんどん投稿され、削除されることもある。 list.txt を作り直すとこんな感じになったとする。

ID001
ID002
ID004
ID005
ID006

ID003 が削除されて ID006 が追加されている。

この状態で上記のやり方でまだダウンロードしていないリストを作るとどうなるか。

$ ls *.mp4 *.flv |gawk '{print $1;}' |cat - list.txt |sort |uniq -u >todo.txt
$ cat todo.txt
ID003
ID004
ID005
ID006

ID003 はダウンロード済みであるにもかかわらずこのリストに現れてしまうのである。

Document ID: faf0085744477f20750c997e764618d5