如何在SWI-Prolog中复制预定义长度/ 2的行为?

dam*_*san 10 prolog clpfd

我试图复制标准长度/ 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

mat*_*mat 5

在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如果尚未提供,请要求您的供应商也实施或更好的替代方案.

  • 一般说明:在教授涉及整数的谓词时,我认为在教学上最好使用有限域约束,因为它们是可以在所有方向上使用的真实关系.没有约束,您将不得不引入非单调谓词来处理整数.`L1#= L0 + 1`给你一个比使用`is/2`更通用的谓词,试试两个版本最常见的查询`my_length(Ls,C,L0,L)`.速度差异易于测量(在严肃的应用中通常可以忽略不计)并且您获得了很多通用性. (3认同)