制御フローには, 二つの重要なカテゴリがあります:
There are two key categories of control flow:
宣言的, その構造の何かの値が制御と次に評価する式の選択を導く. 例えば if
式, switch
式など
手続き的, 正規の制御フロープロを放棄して, プログラマの唐突な指令にしたがって制御が変わる. 例えば break
, continue
など. return
と throw
も.
declarative, when the structure of some value guides control and the selection of the next expression to evaluate, like in if
and switch
expressions;
imperative where control changes abruptly according to a programmer’s command, abondoning regular control flow; examples are break
and continue
, but also return
and throw
.
手続き的な制御フローはしばしば状態変化やエラー処理や I/O など副作用の匂いと密接に絡み合っています.
Imperative control flow often goes hand-in-hand with state changes and other flavors of side-effects, such as error handling and input/output.
return
from func
通常, 関数の結果はその本体の値です. たまに本体の評価中, 評価を完了する前に結果が得られることがあります. このような状況では, 計算の残りを放棄して, その結果を持って直ちに関数を抜けるのに, return (exp)
構成子を使えます. 許される場所では, 同様に throw
がエラーを持って計算を放棄するのに使われます.
Normally, the result of a function is the value of its body. Sometimes, during evaluation of the body, the result is available before the end of evaluation. In such situations the return <exp>
construct can be used to abandon the rest of the computation and immediately exit the function with a result. Similarly, where permitted, throw
may be used to abandon a computation with an error.
関数で返値が単位型のときには, 省略して reutrn
を使うことができますが, これは return ()
と同値です.
When a function has unit result type, the shorthand return
may be used instead of the equivalent return ()
.
Motoko では何種類かの繰り返し構成子を:
Motoko provides several kinds of repetition constructs, including:
for
式は構造化データのメンバ上を繰り返す
loop
式はプログラム上の繰り返し (終了条件はオプション)
while
は入場条件のあるプログラム上の繰り返し
for
expressions for iterating over members of structured data.
loop
expressions for programmatic repetition (optionally with termination condition).
while
loops for programmatic repetition with entry condition.
これらはどれも label (name)
限定子を前置して, ループにシンボル名を付けることができます. 名前の付いたループは制御フローを変更して入り口から続けるとか, 抜けるとかには便利です.
Any of these can be prefixed with a label <name>
qualifier to give the loop a symbolic name. Named loops are useful for imperatively changing control flow to continue from the entry or exit of the named loop.
continue <name>
でループに再突入する
break <name>
でループ全体を抜ける
re-entering the loop with continue <name>
, or
exiting the loop altogether with break <name>
.
下の例は, あるテキストの文字上をループする for
式で, 感嘆符にぶつかったら即繰り返しを中断します.
In the following example, the for
expression loops over characters of some text and abandons iteration as soon as an exclamation sign is encountered.
import Debug "mo:base/Debug";
label letters for (c in "ran!!dom".chars()) {
Debug.print(debug_show(c));
if (c == '!') { break letters };
// ...
}
それほどよく使われるわけではありませんが, 特定の状況では便利な label
の使い途がもう二つあります.
There are two other facets to label
s that are less mainstream, but come in handy in certain situations:
label
は型付けできる
(ループに限らず) 任意の式もラベルを前置することで名前を付けることができる; break
すると式の評価を短絡して, その結果を即値で与えられる (これは関数を reutrn
で途中で抜けるのに似ている. しかし, 宣言と関数呼び出しのオーバヘッドはない)
label
s can be typed
any expression (not just loops) can be named by prefixing it with a label; break
allows one to short-circuit the expression’s evaluation by providing an immediate value for its result. (This is similar to exiting a function early using return
, but without the overhead of declaring and calling a function.)
型注釈付きラベルの構文は label <name> : <type> <expr>
で, <expr>
の値として <alt-expr>
の値を返す break <name> <alt-expr>
構成子を使って任意の式から抜け出すことを意味しています.
The syntax for type-annotated labels is label <name> : <type> <expr>
, signifying that any expression can be exited using a break <name> <alt-expr>
construct that returns the value of <alt-expr>
as the value of <expr>
, short-circuiting evaluation of <expr>
.
これらの構成子を賢く使えば, プログラマはもっとも重要なプログラム・ロジックに焦点を当てて, 例外的な状況は break
を使って処理する, と言うようなことができます.
Judicious use of these constructs allows the programmer to focus on the primary program logic and handle exceptional case via break
import Text "mo:base/Text";
import Iter "mo:base/Iter";
type Host = Text;
let formInput = "us@dfn";
let address = label exit : ?(Text, Host) {
let splitted = Text.split(formInput, #char '@');
let array = Iter.toArray<Text>(splitted);
if (array.size() != 2) { break exit(null) };
let account = array[0];
let host = array[1];
// if (not (parseHost(host))) { break exit(null) };
?(account, host)
}
当然, 普通のラベル付きの式は continue
はできません. 型付けの面から言って, <expr>
と <akt-expr>
の型はラベルで宣言した <type>
を充たさなければなりません. ラベルが <name>
だけ与えられた場合にはその <type>
はデフォルトで単位型 (()
) になります. 同様に <alt-expr>
のない break
は単位値 (()
) の省略形です.
Naturally, labeled common expressions don’t allow continue
. In terms of typing, both <expr>
and <alt-expr>
's types must conform with the label’s declared <type>
. If a label is only given a <name>
, then its <type>
defaults to unit (()
). Similarly a break
without an <alt-expr>
is shorthand for the value unit (()
).