(これはその質問へのフォローアップです)。
どちらが正しいかの書き方lead1(Xs,Ys)
は、 iffは先頭の用語をすべて削除しYs
た接尾辞です。したがって、先頭の s を削除する代わりに、この質問は先頭の s の削除に関するものになりました。Xs
s(s(0))
0
s(s(0))
元の質問と比較して、難しさはここで and のケースを適切に処理することにs(X)
ありs(s(X))
ます。
(これはその質問へのフォローアップです)。
どちらが正しいかの書き方lead1(Xs,Ys)
は、 iffは先頭の用語をすべて削除しYs
た接尾辞です。したがって、先頭の s を削除する代わりに、この質問は先頭の s の削除に関するものになりました。Xs
s(s(0))
0
s(s(0))
元の質問と比較して、難しさはここで and のケースを適切に処理することにs(X)
ありs(s(X))
ます。
if_/3と=/ 3 を使用したバージョンは次のとおりです。
list_suffix([],[]).
list_suffix([X|Xs],S) :-
if_(X=s(s(0)), list_suffix(Xs,S), S=[X|Xs]).
地面の最初の引数を持つクエリは、決定論的に成功します。
?- list_suffix([s(0)],S).
S = [s(0)].
?- list_suffix([s(0),s(s(0))],S).
S = [s(0), s(s(0))].
?- list_suffix([s(s(0)),s(0),s(s(0))],S).
S = [s(0), s(s(0))].
?- list_suffix([s(s(0)), s(s(0)),s(0),s(s(0))],S).
S = [s(0), s(s(0))].
リストが s/1 とは異なる用語で構成されている場合、f(_)
2 番目のリストが最初のリストと同一であるとします。
?- list_suffix([f(_)],S).
S = [f(_G201)].
?- list_suffix([f(_)],[]).
false.
部分的にインスタンス化されたリストも同様に機能します:
?- list_suffix([X, s(s(0)),s(0),s(s(0))],S).
X = s(s(0)),
S = [s(0), s(s(0))] ;
S = [X, s(s(0)), s(0), s(s(0))],
dif(X, s(s(0))).
最も一般的なクエリも同様に機能しますが、不当な方法で回答をリストしています。
?- list_suffix(X,Y).
X = Y, Y = [] ;
X = [s(s(0))],
Y = [] ;
X = [s(s(0)), s(s(0))],
Y = [] ;
X = [s(s(0)), s(s(0)), s(s(0))],
Y = [] ;
.
.
.
ただし、これは、ゴールの長さ/2 をプレフィックスとして付けることで解決できます。
?- length(X,_), list_suffix(X,Y).
X = Y, Y = [] ;
X = [s(s(0))],
Y = [] ;
X = Y, Y = [_G155],
dif(_G155, s(s(0))) ;
X = [s(s(0)), s(s(0))],
Y = [] ;
X = [s(s(0)), _G79],
Y = [_G79],
dif(_G79, s(s(0))) ;
X = Y, Y = [_G155, _G158],
dif(_G155, s(s(0))) ;
X = [s(s(0)), s(s(0)), s(s(0))],
Y = [] ;
.
.
.
Hiere は、前の質問に対する私の回答を翻案したものです。これは、freeze/2 の代わりに when/2 を使用することを示しています。freeze/2 は、最初の引数の非 var/1 条件のみに従います。when/2 は、より複雑な条件に従うことができます。
lead(X, Y) :- var(X), !, freeze(X, lead(X,Y)).
lead([X|Y], Z) :- \+ ground(X), !, when(ground(X), lead([X|Y],Z)).
lead([s(s(0))|X], Y) :- !, lead(X, Y).
lead(X, X).
ここにいくつかの実行例があります。前の回答に与えた回答と同様の例を選択しています。リスト引数が徐々にインスタンス化されるときに、 when/2 が独自の条件をどのように適応させるかがわかります。
?- lead([s(0),s(s(0)),s(s(0)),s(0)],Y).
Y = [s(0), s(s(0)), s(s(0)), s(0)].
?- lead([s(s(0)),s(s(0)),s(s(0)),s(0)],Y).
Y = [s(0)].
?- lead([X,s(s(0)),s(s(0)),s(0)],Y), X=s(_).
X = s(_G3686),
when(ground(_G3686), lead([s(_G3686), s(s(0)), s(s(0)), s(0)], Y)).
?- lead([X,s(s(0)),s(s(0)),s(0)],Y), X=s(0).
X = s(0),
Y = [s(0), s(s(0)), s(s(0)), s(0)].
?- lead([X,s(s(0)),s(s(0)),s(0)],Y), X=s(s(_)).
X = s(s(_G3713)),
when(ground(_G3713), lead([s(s(_G3713)), s(s(0)), s(s(0)), s(0)], Y)).
?- lead([X,s(s(0)),s(s(0)),s(0)],Y), X=s(s(0)).
X = s(s(0)),
Y = [s(0)].
freeze/2 と when/2 はコルーティング プリミティブです。それらの純粋さは、文献で十分に文書化されています。このソースによると、コルーティングを備えた最初の Prolog システムは、geler/2 プリミティブを備えた Prolog-II でした。ソースは、ブートストラップ制約ソルバーへのコルーティングの重要性についても言及しています。
純粋性が可換性でテストされると仮定します。サンプル テストは次のとおりです。
?- lead([X,s(s(0)),s(s(0)),s(0)],Y), X=s(s(0)).
X = s(s(0)),
Y = [s(0)].
?- X=s(s(0)), lead([X,s(s(0)),s(s(0)),s(0)],Y).
X = s(s(0)),
Y = [s(0)].
しかし、最初の回答ですでに書いたように、「最後に」何かをする必要があるかもしれません。クエリの後に、一連の目標を達成できない可能性があることを意味します。制約プログラミングでは、ラベル付けを開始します。
また、freeze/2 と when/2 は、制約ソルバーができるように、目標を組み合わせることで初期の失敗を見つけることができません。
上記の例は、インポートなしでSWI-Prologで実行されます。Jekejeke Prolog では、Minlog 拡張機能とインポート ライブラリ (term/suspend) を使用します。