どもです,@nobkz
Haxeのマクロ技法その1
はじめに。
さてさて、Haxeには強力な言語機能としてマクロがあります。しかし、マクロの技法を知らず、言語機能として良く分からないものとして避けている人が多いのではないでちしょうか?
僕は、マクロむしろ適切なところで、使えば、すごく強力だと思っています。構文が短かくなったり、読みやすくなり、リファクタリングがしやすくなったりすることがあるとは思います。
それで、これから、マクロの様々な技法を紹介していきたいと思います。
基本的に僕のマクロの発想の多くは、Lispからやってきています。そして、この記事は、Lispのマクロについての良著である、OnLispから着想を得ています。というか、OnLispでは、さまざまなマクロが紹介されています。それをHaxeでやるとどなるか?というものをやってみようという記事です。
アナフォリックマクロ
アナフォリックマクロとは?
OnLispでは、沢山のマクロの技法が紹介されていますが、そのなかでアナフォリックマクロというのがあります。それをやってみましょう。
さてさて、日常会話で、前のもを示すことありますよね? 「Lispやったことあるかい?」「あるある! 『それ』良いよね」という「それ」っといったものです。このようなのは、アナフォラ(前方照応)というものです。
さて、プログラミングは言語です。それをhaxeのマクロでやろうというわけです。
アナフォリックなカウンター
さて、まずは、アナフォリックな事例を上げようかと思います。サンプルとして次の、マクロを作ってみたいと思います。
class Test {
static function main() {
loop("I am a lisper and haxer".split(" "),{
trace(element);
trace(counter);
});
}
}
このプログラムは、変数elementと、変数counterの宣言がありませんね? しかし、変数名なんとなく、やりたいことが見えてきませんか?
変数elementは、ループの要素の値が、変数counterは、ループのカウンタであってほしいのです。つまり、このプログラムを実行すると次の出力が得られるように、したいのです。
Test.hx:4: I
Test.hx:5: 0
Test.hx:4: am
Test.hx:5: 1
Test.hx:4: a
Test.hx:5: 2
Test.hx:4: lisper
Test.hx:5: 3
Test.hx:4: and
Test.hx:5: 4
Test.hx:4: haxer
Test.hx:5: 5
普通、こういったループを書くのであれば、このように書くと思います。
class Test {
static function main()
{
var counter = 0;
for( element in "I am a lisper and haxer".split(" ") ){
trace(element);
trace(counter);
counter++;
}
}
}
さて、この変数宣言や、forの構文をマクロに任せれば良いのです。つまり、このような、マクロの実装になります。
class Test {
static function main() {
loop("I am a lisper and haxer".split(" "),{
trace(element);
trace(counter);
});
}
macro static function loop(iterator, block){
return macro {
var counter = 0;
for( element in $iterator ){
$block;
counter++;
}
};
}
}
一応、counterの変数の影響範囲も考え、ブロックを作り、スコープを作っています。
はい、簡単ですね? 何が難しいのでしょう?
今日はここまで
今後も、マクロを使った、技法をいろいろ紹介していきたいと思います。