「便りがないのは良い便り」という言は少なくともブログではあまり通用しない物言いですが、ともあれ無病息災で過ごしています。まとまったことを書けるようになったわけでもないのですが、短信程度の近況報告です。開発中のエスペラント翻訳システムのコードを勘定してみたら、この間どうやら2万行を超えたようです。
2万行と過ごした2年間
私はウェブサイトのカウンタを付けていませんし、Apacheの生ログで正確なアクセス数を勘定出来るにしてもアクセス数に一喜一憂しているわけでもありませんので、いわゆる「切り番」を祝うようなことはしていないのですが、自分のやったことが数字として積み上がっていることを再確認出来たと思っています。
Linuxカーネルの行数がこの間1000万行を超えたというニュースに比べれば微々たるものです。また、肝心要の構文解析・意味解析・構造転換・その後の生成系処理などは殆ど実装されていない状態です。さらに、現在のコードに連なる形で最初に実装を始めたのは2006年の11月頃だったかと記憶していますので、丸2年掛けてようやく到達したということになります。自分自身でもかなり遅々とした歩みだと感じますし、ここ半年はあまり時間を割けていないことも心苦しいのですが、ともあれざっとコードを見返してみても、色々なことがあったな、と物思いに耽ってしまいました。
コードの近況
オブジェクト指向の洗礼
この半年は、流石に「ムーアの法則に期待して、かなり遅くなってもいいから見通しの良いシステムにしよう」ということを発起し、関数型モジュールを軒並みオブジェクト指向モジュールに書き換えたりするなど、システムの体質改善に努めて参りました。この「ムーアの法則に期待」という辺り、システムの完成を直近に置いていない甘えが出ているのかも知れません。ただし、システムは保守の期間の方が長く、工数も多くなるものですので、そういった面でも良い決断だったと思っています。心なしか開発生産性も上がったような気がしますし。
そもそも開発が長期化すればするほど、開発途上で別の箇所のモジュールに触れたり、或いはそこを直したりする場合に、昔のことを思い出すのが辛くなります。どこの会社でもありがちですが、ドキュメントなんてものは開発が終わってから作られるようなものですし、個人で細々と開発しているようなシステムであればなおのことその傾向が強まります。
単純なアクセッサやミューテータをシコシコ実装するのは無駄とはいえ、どうしてもオブジェクト指向として手を加えるとコードは長大化してしまいます。あっという間に当たり前のように語られるようになったMooseを使う方法も考えましたが、いきなり大規模な翻訳システムに使う勇気がまだ湧いてきません。勿論Mooseはゲッタやセッタのコードが減るだなんて単純かつ皮相的な内容がすごいのではなく、Perl 5系で賢いオブジェクト指向開発が出来るからすごいのですが。
増えるワカメ、または空気を吸った布団圧縮袋
閑話休題、手を加えるついでに色々目に付いたところを書き直していったら、あまり機能面での進歩がないまま、コード量は膨れ上がってしまったということです。大掃除の際に本を片付けようと手に取ったら最後、気付いたら本の最終ページをめくっていたとか、気付いたら読んだ本の山の影が夕陽によって遠く伸ばされていただとか、そういうどうしようもない経験も思い出されました。
例えば、ものの十数行で実現していた字句解析(lexical analyzer)が、気付いたら1000行を超えていたということが挙げられます。字句解析とは名ばかりの単なる正規表現でちょちょいと入力文をsplitしただけの状態から、Text::Sentenceよりも偏執的なトークン切り出しを行えるようになった現状まで、そこには色々な紆余曲折があったわけですが、その辺りの細かい話はまた日を改めると言うことで。
なお、ここでいう「行」とは、先のLinuxカーネルと同様、コメント行や空行を含む値です。処理行(ステップ数という表現は必ずしも妥当ではないのですが、ともあれざっくりとした定義ではステップ数)としてもLinuxカーネルと同様に大体7掛けから6掛けの範囲に収まるのではなかろうか、と見積もっています。
文章内単語訳で熟語翻訳が可能になります(近日中)
なお、一つ、現在の文章内単語訳にすぐに反映出来そうないいことがあります。それは、熟語訳を出すということです。
実は、と前置きしなくてもお気付きかも知れませんが、文章内単語訳では、現在は熟語の辞書引きを無視しています。例えばAraba Maroは単語で辞書引き出来ても、Mi iros Araban Maron.だとか、Ĉi tiu loko estas Araba Maro.だとかという文章では、正しく「アラビア海」という熟語が結果に表れませんでした。
それというのも、入力文を単語の配列にぶった切って、後は各単語毎に辞書引きをしているという「手抜き」が原因なのですが、いざ手を抜かずにやろうとすると実装が面倒なので今の今まで放置していたのです。現在は「次の語」を見て熟語かどうかを判断するということを簡単に実装出来るようになりました。
「そんなもの、語の配列と、処理させる添え字を渡しておけばいいじゃないか」とか「Data::Aliasを使えば綺麗かつ速いじゃないか、ダミアン先生もお勧めだぞ」ということは容易に考えられますが、これがまた、色々後続の処理で面倒なことが増えるんですよ。
この辺りの詳細も「ブログのネタを取っておく」という貧乏風に吹かれて後日ということにしますが、ともあれ日に日に複雑度を増していくシステムでは、個々の部品は単純明快な仕組みにしておかないと、後になればなるほど泣きを見ることになります。
階層の回想
語 is a 文 is a 文章 is a 文書という、或る意味では綺麗なクラス階層に落とし込んだことで、今後の構文解析・意味解析辺りにも効果は大きいと感じています。
また、HPSGでも使う素性構造も単純にPerlのクラス階層に読み替えることで、これもまた素直な実装になりました。IST(immediate supertype)を求めたり、型の単一化の際にLUB(least upper bound type)を求める処理などは、流石にCPANには(私の探した限りでは)そのものずばりのモジュールもなかったので、かなり実装する羽目になりましたが(例えばLingua-Featuresディストリビューションは素晴らしい作品ですが、unionが出来るだけでunify(unification)は出来ません)。
はい、お察しの良い皆様はおわかりですが、この辺りの言及もまたの機会に……。
展望:クリスマスまでに完成させます!
断言しましょう。このシステムはクリスマスまでに完成させます、と。政治的に正しく表現するならホリデーシーズンまでには。
ところで、早期からの過剰な最適化は身を滅ぼす、という金言に則り、今のところコードのほぼ全てをPerlで実装しています。Perlでなかったら下手をしたらコードは十倍にも膨らむかも知れない、という箇所もあれば、素直にPrologなどで実装すれば(単一化処理などの基本モジュールの分析・設計・開発・試験の手間が省けて)楽だったのに、と思う箇所もあります。とはいえ、まずはPerlで一通りの機能を実現出来るようになるまで、このまま走っていこうと思っています。
……何故敢えて急にPerlの話を持ち出したかというと、Perl 6がクリスマスに完成するというお約束ネタから類推していただければ幸甚です。
ということで、いつかは最適化のために必要に応じて肝の箇所をXS化しようとも思いつつ、ひとまず今回はここまで。