Factorに入門する(9) マクロでFizzBuzz
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
ま、これでも動くんですが、「引数がすべてリテラル」の条件が満たせてないので、速度のメリットもないですね。マクロについてはまた改めてとりあげようと思います。