resule_goals()の仕様は以下のようになっている。
Inline q *resume_goals(allocp, x, y)
q * allocp;
q x;
q y;
x は中断レコード、または、generator用の構造(struct generator_susp) を直接差すポインタであり、y は具体化対象となる項である。 allocpはヒープ割付点のアドレスであり、戻り値として、 更新されたヒープ割付点アドレスが返される。
メモリ不足のためにconsumerが失敗することがあるが、この場合には、 「現在行おうとしている単一化の処理はキャンセル」する。 つまり、フック構造は残しておき、再度当該具体値(y)と単一化を行うような ゴールをエンキューして終了。
それ以外の結果であれば、method_result に返された値を 新しい値とし、再度objectを含めた鎖構造を再構成し、単一化を 行う(enqueue_unify_goal())。
どちらにしても、エンキューを行った結果、next fieldは他のゴールへの ポインタが記録され、下位2bitは00、つまり、タグ部はREFになる。
このように、1つのゴールに対して重複して再開処理が行われるのは、 multiple wait, いわゆる``OR待ち''(図5.3参照)があるためである。
|
mwait(A, _) :- wait(A) | ... % (1) mwait(_, B) :- wait(B) | ... % (2) |
つまり、goal recordはその 中断原因となった変数にフックするが、複数の中断原因がある場合にはその すべてにフックするが、再開は1度しか行ってはならない。 例えば、図5.3で、変数A,B 共に未定義であると、これは multiple waitになる。その後、Aが先に具体化されたならば、(1)の節が選択され、 (2)の節の実行は廃棄され、後にBが具体化されたとして実行されてはならない。 この言語仕様を満足させるために、 これまで説明したような実装となっている。