case
¶Gforth は、 拡張 case
を提供することで、 上で説明した複数出口ループの問題を解決する追加のオプションを提供します。 この拡張
case
の移植可能な実装は compat/caseext.fs にあります。
この拡張には 3 つの追加ワードがあります。 1 つ目は ?of
で、 case
内で(単なる同等性のテストではなく、)一般的なテストが可能です。 例:
: sgn ( n -- -1|0|1 ) ( n ) case dup 0 < ?of drop -1 endof dup 0 > ?of drop 1 endof \ otherwise leave the 0 on the stack 0 endcase ;
注意: endcase
は値(a value)を drop することに注意してください。 これは of
ではほとんどうまいこと機能しますが、 ?of
ではたいていうまいこといかないので、 今回も endcase
で drop
するための値として 0 をスタック置きます。 ここでは、 sgn
に渡される n は、 いずれの ?of
もトリガーしない場合返り値の 0 そのものになります。
2 番目の追加ワードは next-case
で、 これにより case
をループに変えることができます。
出口が3つのループは以下のようになります:
case condition1 ?of exit-code1 endof condition2 ?of exit-code2 endof condition3 ?of exit-code3 endof ... next-case common code afterwards
ご覧のとおり、 これにより、 先程議論したバリエーションの両方の問題が解決されます(see Begin
loops with multiple exits)。 注意: endcase
とは異なり、 next-case
は値をドロップしないことに注意してください。
13
最後の追加ワードは contof
です。 これは endof
の代わりに使用され、
ループを終了する代わりに次の反復を開始します。 これは、 ダイクストラのガード付きコマンド 繰り返し: do と同様の方法で使用できます。 例:
: gcd ( n1 n2 -- n ) case 2dup > ?of tuck - contof 2dup < ?of over - contof endcase ;
ここで、 2 つの ?of
はループを継続する異なる方法を持っています。 どちらの ?of
もトリガーされない場合、 2
つの数値は等しく、gcd(最大公約数) になります。 Endcase
はそれらの 1 つを削除し、もう 1 つは n として残します。
これらのワードを組み合わせることもできます。 以下は、 endcase
を除く、 各 case
ワードをそれぞれ 1
回使用する例です:
: collatz ( u -- ) \ print the 3n+1 sequence starting at u until we reach 1 case dup . 1 of endof dup 1 and ?of 3 * 1+ contof 2/ next-case ;
この例では、 シーケンスの現在の値をスタックに保持します。 1 の場合、 of
がトリガーされ、 値が削除され、 case
構造から去ります。 奇数の場合、 ?of
がトリガーされ、 3n+1 が計算され、 contof
で次の反復が開始されます。
それ以外の場合、 数値が偶数の場合は 2 で除算され、 next-case
でループが再開されます。
next-case
は、 他の case
ワード群とは異なり、
名前にハイフン(-
)が含まれています。 VFX Forth には値をドロップする nextcase
があるので、これと区別するためです。