我试图复制标准长度/ 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.
Run Code Online (Sandbox Code Playgroud)
简单实用:
my_length([], 0).
my_length([_|T], N) :- my_length(T, X), N is 1+X.
Run Code Online (Sandbox Code Playgroud)
有一些问题.在案例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).
Run Code Online (Sandbox Code Playgroud)
正如@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).
Run Code Online (Sandbox Code Playgroud)
它可以使用zcompare/3CLP(FD)库进行修复.请参阅:https://stackoverflow.com/a/15123146/1545971
在SWI-Prolog中,非确定性问题可以通过CLP(FD)来解决zcompare/3,它将不平等性化为可用于索引的术语:
:- use_module(library(clpfd)).
my_length(Ls, L) :-
zcompare(C, 0, L),
my_length(Ls, C, 0, L).
my_length([], =, L, L).
my_length([_|Ls], <, L0, L) :-
L1 #= L0 + 1,
zcompare(C, L1, L),
my_length(Ls, C, L1, L).
Run Code Online (Sandbox Code Playgroud)
您的示例现在是确定性的(因为最近版本的SWI-Prolog执行即时索引):
?- my_length(Ls, 3).
Ls = [_G356, _G420, _G484].
Run Code Online (Sandbox Code Playgroud)
所有严肃的Prolog实现都附带了CLP(FD),在这里使用它非常有意义.zcompare/3如果尚未提供,请要求您的供应商也实施或更好的替代方案.