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
があるので、これと区別するためです。