Prolog 写経記 その 90 repeat/1

(ほぼ) 毎日淡々と Prolog を写経します.元ネタはこちら.

Prologユーティリティライブラリ

Prologユーティリティライブラリ

今日は repeat/1 を写経します.
順番的には for/1 なのですが,その中で repeat/1 を使ってるのだ.

解説

P が満足されるまで Q を実行する repeat Q until P を実現する.QP は両方共に Prolog のゴールである.

ふむ.

モード

repeat(+)

ふむ.

定義

では,こいつの定義を写経しませう.

:- op(900, fx, repeat).
:- op(850, xfx, until).
repeat Q until P :-
	repeat,
	call((Q, !)),
	call(P).

すっかりお馴染みのオペレータ宣言に,随分シンプルな述語の本体.
ちょっと引っかかるのは述語本体の

	call((Q, !)),

でしょうか.ここには「Q についてのバックトラックはない」という注釈が付いています.
さらに,「注記」に重要なことが書いてあるのでそちらを先に.

注記

repeat/1P が失敗したとき Q についてのバックトラックをせず,むしろ Q を再度呼び出す.repeat/1とみ込み述語の repeat/0 を取り違えないように.

ふむ.
つ・ま・り
述語の定義にある

	call((Q, !)),

のカットがないと,繰り返しの終了条件 P が失敗する度に,つまり繰り返しの度に繰り返しの本体 Q がバックトラックされちゃうということですね.
それは困るのでカットが必要,と.なるほど.

では使用例を写経しませう.

get_filename(F) :-
	repeat (
		write('Filename?'),
		read(F)
	)
	until exists_file(F).

これまた対話的ですね.
これの使用例はないので適当に試すべし.

2 ?- get_filename(F).
Filename?'util.swi'.

F = 'util.swi' 

Yes
3 ?- get_filename(F).
Filename?notfound.
Filename?'memo.swi'.

F = 'memo.swi' 

Yes

ふむ.