Factor入門第8回。今回は、Factorに多々あるcombinatorのうち、"dip combinators"について調べます。factorのcombinatorとは、combinatory logicでいうcombinatorのようなのですが、これを調べるのは、また後日。先に実例で理解しましょう。

ではdipです。documentの説明をみてみましょう。

The dip combinators invoke the quotation at the top of the stack, hiding the values underneath:

よくわからんですね。試してみましょう。

( scratchpad ) 1 2 3 [ / ] dip
--- Data stack:
1/2
3
( scratchpad ) clear
( scratchpad ) 1 2 3 4 [ / ] 2dip
--- Data stack:
1/2
3
4
( scratchpad )

dipは、「スタックトップのquotationを実行する。ただし、quotationの下にある値はいったんどけておき、quotation実行後に戻す。という動作をしています。dipのstack effectは( x quot -- x )となっていますが、この"x"がどけておく値ですね。

2dipの場合は、quotationの下にある値2つをどけています。この「どけておく先」を、factorでは"retain stack"といっているようです。

さて、前回にひきつづきFizzBuzz。dipをつかって書き直してみます。

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

前回とはword fb見た目がまったく違います。よりシンプルですが、pickして2dipして?、って流れは、ちょっと考えないとおいて行かれます。fried quotationに比べるとトリッキーな感じです。

このコード例はこの記事にそっくりなのは偶然、ではなく、先にカンニングしていたからです。

FizzBuzzを最初に書いた後、他に書いてるひとはいないかな? と思って探してみつけました。しかしその時点では2dipが分からなくて読めず。ようやく、自力で2dipがつかえるところに辿り着きましたよ。