Enum
組込みオブジェクトこの章では組込み変数領域が初めから備えている
Enum
組込みオブジェクトを定義する。
Enum
はスクリプトで扱われる列挙オブジェクト
に対応する Type
のインスタンスである。
列挙オブジェクトとは、値を順番に取出す操作が行えるオブジェクトである。値を順番に取り出す操作
(列挙) は toNext
メソッドとitem
プロパティによって行う。
列挙オブジェクトは、0 個以上のオブジェクトを列挙する。列挙の内容は 列挙オブジェクトによって異なる。一般に、 列挙オブジェクトが列挙するオブジェクトは有限個とは限らない。
列挙オブジェクトは、全て Enum
のインスタンスである。
開始列挙オブジェクトとは列挙オブジェクトの一種であり、 オブジェクトの列挙を開始する始まりの列挙オブジェクトである。
Enum
のメンバprototype
Object.prototype
を準プロトタイプとするオブジェクト。name
"Enum"
map
メソッド@[func, enum] {
@if $args.count == 0:
@throw NumberOfArgumentsError[];
@var enums = $args;
enums.shift[];
@var toNext = @{
@for i : 1 ~ enums.count:
@if !(enums[i] = enums[i].toNext[]):
@return enums[i];
@this.item = func[[enums.map[& #.item]]];
@return @this;
};
@return Enum[toNext, @this];
}
このメソッドは、いくつかの列挙オブジェクトで同時に 列挙を行い、それぞれの列挙オブジェクトで列挙されたオブジェクトを引数として 関数を呼出し、その結果を列挙する列挙オブジェクトを返す。
例えば、以下のコードを実行すると、2, 6, 12, 20, …, 110 を表す整数オブジェクトを要素とするリストオブジェクトが得られる。
Enum.map[& #1 * #2, 1 ~ 10, 2 ~ 11].toList[]
zip
メソッド@[enum1, enum2] {
$args.prepend[List.of];
@return Enum.map[[$args]];
}
Enum
の内部メンバ$prototype
Type.prototype
Enum
の関数としての呼出しEnum
は関数として呼出し可能であり、
関数として呼出されると次の処理を行う:
NumberOfArgumentsError
のインスタンスを投げる。$prototype
内部メンバを作成し、その値を
Enum.prototype
とする。toNext
という名前のメンバを作成し、呼出しにおける一つ目の引数をその値とする。#source
という名前のメンバを作成し、二つ目の引数をその値とする。Enum
の関数としての呼出しは、
二つ目の引数を元にして、一つ目の引数として与えられた関数オブジェクトを
toNext
メソッドとして使って列挙を行う簡単な開始列挙オブジェクトを作成する。
列挙オブジェクトは以下のプロパティを持つものと見なす。
toNext
メソッドitem
プロパティの値は最初に列挙されるオブジェクトである。ただし、
列挙されるオブジェクトが一つもなければ、結果の値は初期の Null.null
である。item
プロパティの値は
この列挙オブジェクトの item
プロパティの値の次に列挙される
オブジェクトである。ただし、この列挙オブジェクトの item
プロパティの値の次に列挙されるオブジェクトが存在しなければ、結果の値は初期の
Null.null
である。item
toNext
メソッドが呼出される前はこのプロパティは必ず存在し、
その値は列挙されるオブジェクトである。スクリプトによって直接
代入または削除されない限り、このプロパティの値は変化してはならない。これらのプロパティは読み取り専用でなくても良い。列挙オブジェクトの
プロパティが toNext
メソッド内部以外のところから代入もしくは
削除されたならば、それ以降その列挙オブジェクトはオブジェクトを
上述の規定通りに正しく列挙しなくても良い。
列挙オブジェクトの toNext
メソッドが一度でも関数として呼出された
後は、そのオブジェクトは列挙オブジェクトでなくなってもよい。
注意: 列挙オブジェクトの toNext
メソッドが呼出された後は、toNext
/item
プロパティに関する規定はない。
これを利用して、列挙オブジェクトを使い回すような動作が一般に認められる。
すなわち、toNext
メソッドが呼出されたときに
(新しい列挙オブジェクトを作るのではなくて) その列挙オブジェクトの
item
プロパティの値を変更した上で
同じ列挙オブジェクトをそのまま返すような実装が認められる。
Enum.prototype
のプロパティhead
メソッド@[count] {
@var toNext = @{
@if --count < 0:
@return @null;
#source = #source.toNext[];
@if #source: {
@this.item = #source.item;
@return @this;
} @else: {
@return #source;
}
};
@return Enum[toNext, @this];
}
skip
メソッド@[count] {
@var toNext = @{
@do:
#source = #source.toNext[];
@while #source && --count >= 0;
@return #source;
};
@return Enum[toNext, @this];
}
map
メソッド@[f] {
@var toNext = @{
#source = #source.toNext[];
@if #source: {
@this.item = f[#source.item];
@return @this;
} @else: {
@return #source;
}
};
@return Enum[toNext, @this];
}
filter
メソッド@[f] {
@var toNext = @{
@while (#source = #source.toNext[]) && !f[#source.item]: ;
@if #source: {
@this.item = #source.item;
@return @this;
} @else: {
@return #source;
}
};
@return Enum[toNext, @this];
}
forAll
メソッド@[predicate] {
@if ## == 0:
predicate = Function.id;
@for i: @this:
@if !predicate[i]:
@return @false;
@return @true;
}
exists
メソッド@[predicate] {
@if ## == 0:
predicate = Function.id;
@for i: @this:
@if predicate[i]:
@return @true;
@return @false;
}
fold
メソッド@[func, init] {
@var e = @this;
@if !@exists $args[2]: {
e = e.toNext[];
@if !e:
@throw UnsupportedOperationError[];
init = e.item;
}
@var v = init;
@for i: e:
v = func[v, i];
@return v;
}
このメソッドは、この列挙オブジェクトで実際に列挙操作を行い、 引数で指定されたに引数関数を用いて各オブジェクトを畳み込む。 第二引数が指定された場合は、それが初期値となる。第二引数が渡されなければ、 最初に列挙されるオブジェクトが初期値となる。
例えば以下のコードは、1 * 2 * 3 * 4
の計算を行い、結果として 24
を返す:
List.of[1, 2, 3, 4].fold[& #1 * #2]
また以下のコードは、0 + 1 + 2 + 3 + 4
の計算を行い、結果として
10 を返す:
List.of[1, 2, 3, 4].fold[& #1 + #2, 0]
toList
メソッド@ { List.of[[@this]] }
列挙オブジェクトが関数として呼出し可能であるかどうか、 および関数として呼出されたときの動作は、一般には規定しない。
オブジェクト O を開始列挙オブジェクトと見なして列挙動作を行い、 全ての列挙結果を得る処理 enumerate-all を、以下のように定義する:
E.toNext[]
を評価し、その結果に対して
get-reference-value
を行い、その結果を改めて
e と置く。ただし、この評価において部分式 E の評価結果は
e であるとする。item
プロパティを取得する。
取得の結果が正常終了でなければ、直ちにそれを返す。正常終了ならば、
その値を V とする。E.toNext[]
の評価 (*1) に戻る。ただし、O がリストオブジェクトならば、上記の代わりに以下の動作を行ってもよい:
elements
内部メンバの値]] を返す。リストオブジェクトに含まれるオブジェクトを列挙し、各オブジェクトを出力する例:
@var list = List.of[1, 2, 3];
@var e = list.getEnum[];
@while e = e.toNext[]:
@printline e.item;
または:
@var list = List.of[1, 2, 3];
@for i : list:
@printline i;
© 2006-2007 Magicant