Gauche:generator

Gauche:generator

Shiro(2012/02/20 02:48:07 UTC): 0.9.3に入るジェネレータに関するもろもろのメモ。

ジェネレータ間の変換

John Nashの暗号器は入力にビット列を取り、ビット列を出力する。この手の(長さがわからない)列を 扱うのに、ジェネレータは便利だ。

gauche.generator には今のところバイトジェネレータを扱うユーティリティはいくつか 用意してるけど、 ビットジェネレータはほとんど無い (整数をビットジェネレータに変換するものだけ) なので、 バイト列とビット列の相互変換を補助関数で定義したんだけど、 こういうジェネレータからジェネレータの変換器をもうちょいうまく抽象化して 書けないかなと思った。つまり、ジェネレータからジェネレータへの変換を 直接書き下すんじゃなくて、「変換生成器」に「入出力要素間の関係」を渡せば 「変換器」を返してくれるような仕組みがほしい。

入力列の1要素に出力列の1要素が対応する場合はgmapが使える。 入力列の1要素に出力列の0または1要素が対応する場合はgfilterが使える。

バイトジェネレータからビットジェネレータは、入力の1要素に出力の8要素が対応する。 ビットジェネレータからバイトジェネレータは逆に、入力の8要素に出力の1要素が対応だ。 入力n、出力mの一般例としては、例えばutf-16列からutf-8列への変換、などが考えられる。

入力1、出力n (n>=0) なら形としてはappend-mapと同じで、 a -> [b] な関数と () -> aなジェネレータを受け取って () -> b なジェネレータを返す変換器にすればいい。

入力の要素数n (n>=1) が一定なら、「変換生成器」側で入力をその個数ごとに切り出して [a] -> [b]な関数に渡せばいい。 ビットジェネレータからバイトジェネレータはそれで書ける

utf-16からutf-8など、入力に依存して必要な要素数が変化する場合はどうしよう。 渡す関数を、入力ジェネレータを受け取って0個以上の出力を返す (() -> a) -> [b] にすれば書けるけど、これじゃあ 最初から欲しい変換器 (() -> a) -> (() -> b) を直接書き下すのに比べて あんまり楽にならないような気がする。

ジェネレータでなく遅延シーケンスなら、 入力リストを普通に頭から眺めて、必要な分だけ取って処理して、 出力 ++ 入力の残りで再帰 すればいいから悩む必要ないんだな。 やっぱりジェネレータよりも遅延シーケンスの方が使い勝手は良いな。


Tag: gauche.generator

More ...