標準のlength/2述語の動作を複製しようとしています。特に、以下の例のように、述語が有界および非有界の引数に対して機能するようにします。
% Case 1
?- length(X, Y).
X = [],
Y = 0 ;
X = [_G4326],
Y = 1 ;
X = [_G4326, _G4329],
Y = 2 ;
X = [_G4326, _G4329, _G4332],
Y = 3 .
% Case 2
?- length([a,b,c], X).
X = 3.
% Case 3
?- length(X, 4).
X = [_G4314, _G4317, _G4320, _G4323].
% Case 4
?- length([a,b,c,d,e], 5).
true.
プレーンでシンプルな実装:
my_length([], 0).
my_length([_|T], N) :- my_length(T, X), N is 1+X.
いくつかの問題があります。ケース3では、正解を生成した後、無限ループに入ります。この述語を決定論的な述語に変換できますか?または、falseで停止する非決定論的ですか?
はい!しかし、赤いカットを使用しています。参照:https ://stackoverflow.com/a/15123016/1545971
しばらくして、組み込みの長さ/2の動作を模倣する一連の述語をコーディングすることができました。my_len_tailは決定論的であり、すべてのケース1〜4で正しく機能します。もっと簡単にできますか?
my_len_tail(List, Len) :- var(Len)->my_len_tailv(List, 0, Len);
my_len_tailnv(List, 0, Len).
my_len_tailv([], Acc, Acc).
my_len_tailv([_|T], Acc, Len) :-
M is Acc+1,
my_len_tailv(T, M, Len).
my_len_tailnv([], Acc, Acc) :- !. % green!
my_len_tailnv([_|T], Acc, Len) :-
Acc<Len,
M is Acc+1,
my_len_tailnv(T, M, Len).
@DanielLyonsがコメントで示唆しているように、clpfdを使用してチェックよりも延期することができます。しかし、それでも1つの問題が残ります。ケース3(my_len_clp(X, 3)
)では、述語は非決定的です。どうすれば修正できますか?
:-use_module(library(clpfd)).
my_len_clp(List, Len) :- my_len_clp(List, 0, Len).
my_len_clp([], Acc, Acc).
my_len_clp([_|T], Acc, Len) :-
Acc#<Len,
M is Acc+1,
my_len_clp(T, M, Len).
zcompare/3
CLP(FD)ライブラリから使用して修正できます。参照:https ://stackoverflow.com/a/15123146/1545971