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