SWI-Prologのマニュアルを読んでいたら、面白そうな述語を見つけました。
6.2 Coroutining
Coroutining deals with having Prolog goals scheduled for execution as soon as some conditions is fulfilled. In Prolog the most commonly used conditions is the instantiation (binding) of a variable. Scheduling a goal to execute immediately after a variable is bound can be used to avoid instantiation errors for some built-in predicates (e.g. arithmetic), do work lazy, prevent the binding of a variable to a particular value, etc. Using freeze/2 for example we can define a variable can only be assigned an even number:
?- freeze(X, X mod 2 =:= 0), X = 3
No
( http://gollem.science.uva.nl/SWI-Prolog/Manual/coroutining.html )
freezeは第一引数に未束縛の変数を指定し、
第二引数に『第一引数の変数が束縛されたときに実行されるゴール』を指定します。
上の例ではXが3に束縛された時点で X mod 2 =:= 0 が実行されます。
とりあえず、使ってみました。
?- [user].
test(Y):- write(1), freeze(X, (write(a),Y is X + 1,write(b))), write(2), X = 3, write(3).
?- test(Y).
12ab3
Y = 4;
no
実行順序はこんな感じ。
1) write(1) が実行 (画面に1が出力)
2) freeze(X, (write(a),Y is X + 1,write(b))) が実行 (引数は評価されない)
3) write(2) が実行 (画面に2が出力)
4) X = 3 が実行
5) Xが束縛されるのをきっかけにfreezeの第二引数が実行される
5a) write(a) が実行 (画面にaが出力)
5b) Y is X + 1 が実行
5c) write(b) が実行 (画面にbが出力)
6) write(3) が実行 (画面に3が出力)
私自身はコルーチンについてはあまり知らないんですが、
これはむしろ変数の束縛をトリガとした遅延評価みたいに感じました。
Schemeのdelayがfreezeに対応して、forceが変数の束縛に対応する感じです。
他にもfrozenという述語があり、これは指定された変数をトリガとしている
freezeオブジェクト(?)を取得できます。
?- freeze(X, write(a)), frozen(X, Y).
X = _G397{freeze = user:write(a)},
Y = user:write(a) ;
No
使い道は現在はいまいち分かってません。
他にもcoroutining関連の述語はいくつかありますが、
それらはまたの機会にでも。
(条件を満たしたときに引数の実行を始めるwhenという述語があるんですが、
なぜか上手くいかなかったorz)