if
式では、プログラムの フロー を変更することを決定できます。他のプログラミング言語と同じように、Verse の if
式は条件付き実行をサポートしていますが、Verse では条件で成功と失敗を使用して判断します。
たとえば、プレイヤーが落下したときにダメージを受けない高さを定義するコードを作成できます。
var PlayerFallHeight : float = CalculatePlayerFallHeight()
# プレイヤーは落下が 3 メートルより大きい場合ダメージをうけます。
if (PlayerFallHeight > 3.0):
DealDamage()
# プレイヤーの落下の高さをリセットします
ZeroPlayerFallHeight()
この例では、PlayerFallHeight
が 3 メートルより大きい場合、条件が満たされ、DealDamage()
が実行されてから、プレイヤーの落下の高さがリセットされます。他の場合は、条件が満たされません。プレイヤーはダメージを受けませんが、プレイヤーの落下の高さがリセットされます。
if
プレイヤーの落下の高さサンプルでは、次の 構文 を使用します。
expression0
if (test-arg-block):
expression1
expression2
expression0
を実行した後、Verse プログラムは if ブロックに入ります。test-arg-block
が成功すると、Verse プログラムは expression1
(1 つの式または式のブロック) を実行します。他の場合は、test-arg-block
が失敗して、Verse プログラムは expression1
をスキップして、expression2
のみを実行します。

if ブロック ロジックのフローチャート
if ... else
if
式が失敗したときに、実行する式も指定できます。
たとえば、プレイヤーの落下が 3 メートル未満であり、ジャンプメーターが 100 パーセントである場合に、ダブルジャンプ能力を獲得するとします。ただし 3 メートル以上落下、またはジャンプメーターが 100 パーセントではない場合、キャラクターの腕が羽ばたくように動き、プレイヤーにダブルジャンプできないことを知らせます。
var PlayerFallHeight : float = CalculatePlayerFallHeight()
if (PlayerFallHeight < 3.0 and JumpMeter = 100):
# ダブルジャンプを実施します。
ActivateDoubleJump()
# プレイヤーのジャンプの高さをリセットします。
ZeroPlayerFallHeight()
else:
# キャラクターの腕が羽ばたくように動いて
# プレイヤーにダブルジャンプできないことを知らせます!
ActivateFlapArmsAnimation()
# ダブルジャンプのクールダウンを設定し、
# ジャンプを素早く押しても「腕を羽ばたくように動く」アニメーションが不適切に再生されないように設定します。
SetDoubleJumpCooldown()
この例では、if
の条件は、PlayerFallHeight
が 3 メートル未満であり、かつ、JumpMeter
が 100 パーセントであるかどうかを評価します。条件が満たされる場合、ActivateDoubleJump()
と ZeroPlayerFallHeight()
が SetDoubleJumpCooldown()
の前に実行されます。
if
条件が満たされない場合、else
に続く式 ActivateFlapArmsAnimation()
が SetDoubleJumpCooldown()
の前に実行されます。
if-else の構文サンプルは次のようになります。
expression0
if (test-arg-block):
expression1
else:
expression2
expression3

if-else ブロック ロジックのフローチャート
if ... else if ... else
プレイヤーが 3 メートルを超えて落下したとき、100 パーセントのシールドがあると、最大のダメージを受けますが、生き延びられます。そしてダブルジャンプ能力を獲得するルールを変更します。落下が 3 メートル未満であり、ジャンプメーターが 75 パーセントを超えている場合に、ダブルジャンプ能力を獲得するようにします。
var PlayerFallHeight : float = CalculatePlayerFallHeight()
if (PlayerFallHeight > 3.0 and shields = 100):
DealMaximalDamage()
return false
else if (PlayerFallHeight < 3.0 and JumpMeter > 75):
ActivateDoubleJump()
return false
else:
return true
# プレイヤーの落下の高さをリセットします
ZeroPlayerFallHeight()
Syntactically, the if-else if-else example looks like this:
expression0
if (test-arg-block0):
expression1
else if (test-arg-block1):
expression2
else:
expression3
expression4

if-else if-else ブロックロジックのフローチャート
if ... then
前のサンプルで if
条件のいずれも、動作を変えることなく、複数の行に記述することができます。
expression0
if:
test-arg-block
then:
expression1
expression2
コードブロック test-arg-block
には 1 つまたは複数行の条件を含められますが、expression2
の前に expression1
を実行するためにすべてが成功する必要があります。他の場合は expression2
のみが実行されます。
この形式でサンプルの if ... else セクションを書き直すと次のようになります。
var PlayerFallHeight : float = CalculatePlayerFallHeight()
if:
PlayerFallHeight < 3.0
JumpMeter = 100
then:
# ダブルジャンプを実施します
ActivateDoubleJump()
# プレイヤーのジャンプの高さをリセットします
ZeroPlayerFallHeight()
else:
# キャラクターの腕を羽ばたくように動かせて
# プレイヤーにダブルジャンプできないことを知らせます!
ActivateFlapArmsAnimation()
# ダブルジャンプのクールダウンを設定し、
# ジャンプを素早く押しても「腕を羽ばたくように動く」アニメーションが不適切に再生されないように設定します。
SetDoubleJumpCooldown()
単一行の式
他のプログラミング言語にある三項演算子のように、if else
を単一行の式として記述できます。たとえば、プレイヤーの ShieldLevel
に基づいて、最大または最小の Recharge
値を割り当てる場合に、次の Verse コードを作成できます。
Recharge : int = if(ShieldLevel < 50) GetMaxRecharge() else GetMinRecharge()
述語の要件
if
の 述語 (プレディケート)、つまり丸かっこ () に囲まれた式は、他のプログラミング言語と異なり、ブール値 (Verse の logic
) を返すことが想定されていません。代わりに、述語に decides
エフェクトがあることが想定されます (一般にサブタイプ化により、述語の全体エフェクトで decides
を含めることが要求される場合、エフェクトセットが許可される場所でエフェクトのサブセットが許可される)。このエフェクトは取り囲むスコープから除去されます。つまり、if
の述語にあるすべての演算子からの decides
エフェクトは、if
構造でなくなります。たとえば、次のコードでは、Main
には decides
エフェクトがありません。もっとも Foo
を呼び出し、そこにあります。
Foo()<transacts><decides> : void = {}
Bar() : void = {}
Main() : void =
if (Foo[]):
Bar()
これは、どのブランチを実行するのかを選択する if
に logic
入力を使用するのではなく、if
の述語に含まれる演算の成功が適切なブランチを決定するのに使用されます。すべての演算が成功した場合は、then
ブランチ、いずれかの演算が失敗した場合は、else
ブランチ (存在する場合) になります。つまり、任意の演算が if
の述語で使用できます。定数の導入も可能であることに注意してください。その例を以下に示します。その例を以下に示します。
Main(X : int) : void =
Y = array{1, 2, 3}
if:
Z0 := Y[X]
Z1 := Y[X + 1]
then:
Use(Z0)
Use(Z1)
言い換えると、then
ブランチのスコープには、if
述語に導入された任意の名前を含められます。
トランザクション動作
他のプログラミング言語と比較して、if
で異なる点は、if
の述語のトランザクション動作です。if
の述語で、no_rollback
エフェクトを指定できません (これは明示的に transacts
、varies
または computes
を指定しないすべての関数で暗示的に使用)。これは、述語が失敗した場合に、述語の実行時におけるすべての演算 (ファイル I/O や コンソールへの書き込みなど、ランタイムの外部リソースに影響する完了していない処理) が、else
ブランチが実行される前に、元に戻されるからです。その例を以下に示します。
int_ref := class:
var Contents : int
Incr(X : int_ref)<transacts> : void =
set X.Contents += 1
Foo(X : int) : int =
Y := int_ref{Contents := 0}
if:
Incr(Y)
X > 0
then:
Y.Contents
else:
Y.Contents
関数 Foo(-1)
は 0
を返し、一方 Foo(1)
は 1
を返します。これは、X > 0
をテストする前に Incr
へのコールが起こりますが、それによる Y
の変更が、else
ブランチの実行前に、元に戻されるからです。Incr
で、transacts
エフェクトを手動で指定する必要があったことに注意してください。デフォルトでは、トランザクション動作は実行されません。暗示的 no_rollback
エフェクトが有効です。ただし、transacts
エフェクトを指定することで追加できます (暗示的 no_rollback
エフェクトをオーバーライド)。