我正在尝试复制标准 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 中,在产生正确答案后,它进入了一个无限循环。这个谓词可以转化为确定性的吗?还是因错误而停止的不确定性?
是的!但使用红色切割。请参阅: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来推迟检查。但它仍然留下一个问题:在案例 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