Factor入門第9回。またFizzBuzzかよ。Factorは今時の言語なので、Lisp的なマクロがあります。

マクロの実例。

( scratchpad ) : ++ ( x -- x ) 1 + ;
( scratchpad ) 2 ++ .
3
( scratchpad ) MACRO: macro++ ( x -- x ) [ 1 + ] ;
( scratchpad ) 2 macro++ .
3
( scratchpad ) 

見た目は普通のword定義に似ています。違いは、quotationをかえすように書かなくてはいけないところ。実行結果はふつうのwordと同じ。

では何が違うのか? というと、

A call of a macro inside a word definition is replaced with the quotation expansion at
compile-time if precisely the following conditions hold:
- All inputs to the macro call are literal
- The word calling the macro has a static stack effect
- The expansion quotation produced by the macro has a static stack effect
If any of these conditions fail to hold, the macro will still work, but expansion will be
performed at run-time.

とのことで、入力がリテラル・マクロを呼ぶwordのスタックエフェクトがstatic・かつマクロが生成するquotationのスタックエフェクトもstaticのときに、コンパイル時に展開されるそうです。

さて、FizzBuzzをマクロで書き直してみます。friedバージョンを書き直しましょう。

IN: fizzbuzz
USING: macros kernel io math math.parser prettyprint sequences fry ;
: modN? ( x n -- ? ) mod 0 = ;
MACRO: fb ( x n str -- x/str )
pick number?
[ '[ _ dup _ modN? [ drop _ ] when ] ]
[ '[ _ _ _ 2drop ] ]
if ;
: pp ( x/str -- ) dup number? [ number>string ] when print ;
100 [ 1 + 15 "FizzBuzz" fb 3 "Fizz" fb 5 "Buzz" fb pp ] each

ま、これでも動くんですが、「引数がすべてリテラル」の条件が満たせてないので、速度のメリットもないですね。マクロについてはまた改めてとりあげようと思います。