制御フロー

サブルーチン

変数 #offset はサブルーチン固有ベクトルである。これはサブルーチンを実行するごとに作られる無名ベクトルである。サブルーチン固有ベクトルの主な目的はサブルーチンが使用する記憶領域をローカル化することである。他のプログラミング言語でグローバル変数 x と ローカル変数 y に相当するものは、パステルステッチではそれぞれベクトル x と y + #offset である。加算 + の右辺を省略すると右辺が #offset であるかのように計算されるので、後者は y + とも書くことができる。結果的には + 記号が他のプログラミング言語でいうローカル変数の記号のように見える。

以下の例では順に 10, 20, 30, 40, 30, 20 が表示される。mulde のかわりに procedure を用いても同様である。

code Localized memories
write: to (x) value (10)
write: to (y +) value (20)
print: [x]
print: [y +]
mulde
 write: to (x) value (30)
 write: to (y +) value (40)
 print: [x]
 print: [y +]
end
print: [x]
print: [y +]
endcode

引数解決の要因のひとつに「呼び出し元ルーチンのサブルーチン固有ベクトルへの移行」がある。詳細は後述するが、結果だけを説明すると、呼び出し元のルーチンでのローカル化された記憶装置の値が、サブルーチンに継承されるということである。

以下の例では順に 10, 20, 10 が表示される。

code Inheritance of localized memories
write: to (x +) value (10)
mulde
 print: [x +]
 write: to (x +) value (20)
 print: [x +]
end
print: [x +]
endcode

サブルーチンを定義する方法には procedure と mulde がある。長大なサブルーチンを作ってしまったとき、それを複数のサブルーチンに分割するには、以下のように段階的に作業を進めるとよい。

  1. サブルーチンの一部を mulde と end で囲む。
  2. mulde を proceude に置き換える。その procedure を呼び出す文を追加する。
  3. 新たな procedure ブロックを独立した code ブロックに移動する。

このうち最も頭を使うのはステップ 1 である。なぜなら、コードの一部を mulde ブロックに入れたことにより、サブルーチンコンテキストが変更されるからである。ここでサブルーチンコンテキストとは、変数の値、制御構文 return で指定された戻り値などのことである。

条件分岐

パステルステッチの条件分岐は if のみで、他のプログラミング言語の else または switch にあたるものは存在しない。else に相当するプログラムを記述するには、条件式の値を記憶装置に保存して、その否定に対して if ブロックを使用すればよい。以下の例では、ローカル化された記憶領域 discriminant is positive + に真偽値を保存している。

code else
procedure quadratic equation
write: to (discriminant is positive +)
> value (0 ≤ #b ∗ #b − (float 4) ∗ #a ∗ #c)
if [discriminant is positive +]
 return: − #b + [square root: #b ∗ #b − (float 4) ∗ #a ∗ #c] / (float 2) ∗ #a
end
if ¬ [discriminant is positive +]
 return: false
end
endcode

ただし、この例は実用的ではない。パステルステッチのサブルーチンの戻り値は、プリミティブ演算 return が実行されなければ false になるので、上記のコードの return: false は冗長である。

同様に、他のプログラミング言語の switch に相当することを行うには、条件分岐の対象となる値をローカル化された記憶領域に保存して、それに対して if ブロックを使用すればよい。

パステルステッチでは、通常の条件分岐よりも、非局所制御フロー構文の if 引数を使用した方がコードが簡潔になる。上記の例と同じことを非局所制御フロー構文を用いて記述すると、以下のようになる。

code Non-local control flow
suggest: if ($verb = quadratic equation) evaluate [echo: false]
suggest: if ($verb = quadratic equation ∧ 0 ≤ $b ∗ $b − (float 4) ∗ $a ∗ $c)
 > evaluate [quadratic equation + when discriminant is positive]
procedure quadratic equation + when discriminant is positive
 return: − #b + [square root: #b ∗ #b − (float 4) ∗ a ∗ c] / (float 2) ∗ #a
end
endcode

ループ

パステルステッチのループは loop ブロックの 1 種類しか存在しない。ループを抜けるには制御構文 break を使用する必要がある。

制御構文 break の引数が省略されている、または論理型の false であるときループを抜ける。パステルステッチでは、引数を省略することと引数の値が論理型の false であることは原則として等価である。制御構文 break もこの原則に従う。また、論理式の値が真であるときループを継続する (すなわち、論理式の値が偽であるときループを抜ける) のは、C 言語の while および for の慣習にも合致する。以下の例では、ループの実行を 10 回だけ繰り返す。すなわち、0 から 9 までの整数を順に表示する。

code Loop
write: to (cn +) value (0)
loop
 break: [cn +] < 10
 print: [cn +]
 write: to (cn +) value ([cn +] + 1)
end
endcode