Perl, Python, Ruby バインディングの追加(marisa-0.2.0-beta5)

概要

marisa-trie に Perl, Python, Ruby バインディングを追加したものを marisa-0.2.0-beta5 としました.使い方は C++ とほぼ同じです.

動作確認をしたのは Ubuntu だけなので,他の環境では動かないかもしれません.

(追記 2011-05-05)C++ と同じようなインタフェースではメソッドの呼び出しにかかるコストがかなり大きくなるようなので,専用のインタフェースを追加することを検討しています.

SWIG について

バインディングの作成には SWIG を使っています.年単位で触っていなかった Perl,さらにまったく使ったことのない Rubyバインディングを作成できたのは SWIG のおかげです.libmarisa のインタフェースが単純ということも理由にはあるでしょうが,思っていたよりは簡単だったという印象です.

SWIG を使うとき,最大の障壁となるのはドキュメントだと思います.「よーし,バインディングを開発しちゃうぞー」という軽いノリで SWIG のサイトにあるドキュメントに手を出すと,間違いなく心が折れます.Read this! と書いてあるセクションだけでも「ごめんなさい」です.実際,何度か「ごめんなさい」しました.

さて,SWIG のことが理解できたでしょうか.私には無理でした.

心を取り戻したら,いろいろなことに目を瞑って,前に進みます.まずは Python バインディングを開発しようと考え,Python 向けのドキュメントに挑みましょう.

再び心を折りにきているとしか思えません.

次に,ポインタと長さで文字列を受け取ったり返したりする方法を調べていると,別のドキュメントへのリンクが見つかります.

徐々に耐性ができてきました.

それから,C++ の例外については,さらに別のドキュメントを参照します.

後は,PerlRuby に関するドキュメントを少し読みました.

実際には必要な部分を拾って読んだだけなのですが,ドキュメントの量には圧倒されました.その有用性にもかかわらず日本語の解説が少ないことに疑問を持っていたのですが,なんとなく理由が分かったような気がします.

かくいう私も解説なんてとんでもないと思ったので,実際に作成したファイルへのリンクを貼るだけにとどめておきます.

最終的には,かなりシンプルに仕上がりました.SWIG のドキュメントを読み始めた段階では,相当に苦労するかもしれないと不安になっていたのに,終わってみれば,何に苦労していたのか不思議になるくらいです.

というわけで,インタフェースがシンプルであれば,SWIG を使って簡単にバインディングを開発できます.なんとなくイメージが掴めるまでは苦労するかもしれませんが,そこから先はサクサク進むと思います.おまけに,インストール用のモジュールを作成する方法までドキュメントに解説があるので,ほとんど使ったことがない言語にも対応できます.「バインディング欲しいなー」と思っている方は,時間を見つけて挑戦してみてはいかがでしょうか.

インタフェース

同じソースコードから Perl, Python, Rubyバインディングを生成しているので,インタフェースはほとんど同じです.言語による違いが少しあるものの,C++ のインタフェースを知っていれば,すぐに使い方が分かります.

Perl バインディング
use marisa;

$keyset = new marisa::Keyset;
$keyset->push_back("apple");
$keyset->push_back("orange");

$trie = new marisa::Trie;
$trie->build($keyset);

$agent = new marisa::Agent;

$agent->set_query("apple");
print "apple: ", $trie->lookup($agent), "\n";

$agent->set_query("banana");
print "banana: ", $trie->lookup($agent), "\n";

$agent->set_query("orange");
print "orange: ", $trie->lookup($agent), "\n";

$agent->set_query("");
while ($trie->predictive_search($agent)) {
  print "predictive_search: ", $agent->key()->str(), "\n";
}
Python バインディング
import marisa

keyset = marisa.Keyset()
keyset.push_back("apple");
keyset.push_back("orange");

trie = marisa.Trie()
trie.build(keyset)

agent = marisa.Agent()

agent.set_query("apple")
print("apple: %s" % trie.lookup(agent))

agent.set_query("banana")
print("banana: %s" % trie.lookup(agent))

agent.set_query("orange")
print("orange: %s" % trie.lookup(agent))

agent.set_query("")
while trie.predictive_search(agent):
  print("predictive_search: %s" % agent.key().str())
Ruby バインディング
require "marisa"

keyset = Marisa::Keyset.new
keyset.push_back("apple")
keyset.push_back("orange")

trie = Marisa::Trie.new
trie.build(keyset)

agent = Marisa::Agent.new

agent.set_query("apple")
print("apple: ", trie.lookup(agent), "\n")

agent.set_query("banana")
print("banana: ", trie.lookup(agent), "\n")

agent.set_query("orange")
print("orange: ", trie.lookup(agent), "\n")

agent.set_query("")
while trie.predictive_search(agent)
  print("predictive_search: ", agent.key().str(), "\n")
end