Recursion Prolog中的子列表谓词

Recursion Prolog中的子列表谓词,recursion,prolog,logic,Recursion,Prolog,Logic,我试图在Prolog中定义一个谓词子列表(X,Y),当列表X中的元素都以与X相同的顺序出现在列表Y中时,该谓词为真 我的方法是取X的头部,在Y中找到头部的第一个实例,并在第一个实例之前剪切列表,然后用X的尾部重复此操作,直到尾部等于空列表 我已经编写了helper谓词cut(X,Y,Z),如果Z是在列表Y中第一个X实例之前剪切所有内容的结果列表,则该谓词为true 我的代码如下: cut(_,[],[_|_]) :- false. cut(X,[H|T],[H|T]) :- X = H, !.

我试图在Prolog中定义一个谓词
子列表(X,Y)
,当列表
X
中的元素都以与
X
相同的顺序出现在列表
Y
中时,该谓词为真

我的方法是取
X
的头部,在
Y
中找到头部的第一个实例,并在第一个实例之前剪切列表,然后用
X
的尾部重复此操作,直到尾部等于空列表

我已经编写了helper谓词
cut(X,Y,Z)
,如果
Z
是在列表
Y
中第一个
X
实例之前剪切所有内容的结果列表,则该谓词为true

我的代码如下:

cut(_,[],[_|_]) :- false.
cut(X,[H|T],[H|T]) :- X = H, !.
cut(X,[_|T],Y) :- cut(X,T,Y).

sublist([],[]).
sublist([],[_|_]).
sublist([A|B],C) :- cut(A,C,Z), sublist(B,Z).
当我询问

?- sublist(L,[1,2,3]).
Prolog没有给出
[1,2,3]
的所有子列表,而是给出以下输出:

L = [] ;
L = [1] ;
L = [1, 1] ;
L = [1, 1, 1] ;
L = [1, 1, 1, 1] ;
L = [1, 1, 1, 1, 1] ;
L = [1, 1, 1, 1, 1, 1] ;
L = [1, 1, 1, 1, 1, 1, 1] ;
L = [1, 1, 1, 1, 1, 1, 1, 1] ;
L = [1, 1, 1, 1, 1, 1, 1, 1, 1] ;
L = [1, 1, 1, 1, 1, 1, 1, 1, 1|...] ;
L = [1, 1, 1, 1, 1, 1, 1, 1, 1|...] ;
L = [1, 1, 1, 1, 1, 1, 1, 1, 1|...] 

我看不出我的错误。有人能给我指出吗?

简短回答:
cut/3
如果找到元素,不会从列表中弹出

第一个答案
L=[]。
是第二个子句触发的结果。现在,下一个答案由最后一个子句生成。因此发生的情况是:

sublist(A,[1,2,3]) :- % C = [1,2,3]
    cut([A|B],[1,2,3],[H|T]) :- % H = 1, T = [2,3], Z = [1,2,3]
        A = H, % A=1
        !.
    sublist(B,[1,2,3]).
(我还冒昧地将条款开头的
X
替换为
H
,使其更加优雅)。现在它生成:

?- sublist(L,[1,2,3]).
L = [] ;
L = [1] ;
L = [1, 2] ;
L = [1, 2, 3] ;
false.
?- sublist(L,[1,2,3]).
L = [] ;
L = [1] ;
L = [1, 2] ;
L = [1, 2, 3] ;
L = [1, 3] ;
L = [2] ;
L = [2, 3] ;
L = [3] ;
false.
请注意,答案不会生成所有列表:例如
L=[2,3]
也是有效答案。这不起作用的原因是
cut/3
具有
,因此不允许引入其他元素。您可以通过以下方法解决此问题:

cut(_,[],[_|_]) :- false.
cut(H,[H|T],T).
cut(X,[_|T],Y) :-
    cut(X,T,Y).
现在我们得到:

?- sublist(L,[1,2,3]).
L = [] ;
L = [1] ;
L = [1, 2] ;
L = [1, 2, 3] ;
L = [1, 3] ;
L = [2] ;
L = [2, 3] ;
L = [3] ;
false.
然而,您可以非常优雅地解决这个问题,而无需使用帮助谓词。我们可以首先构造一个谓词来验证/创建列表:

list([]).
list([_|T]) :-
    list(T).
接下来,我们声明,如果
X
为空,则您并不真正关心右边是哪种类型的列表:

sublist([],L) :-
    list(L).
最后,如果
X
不是空的,我们需要在某处获得
HX
(X
的头部)。如果我们找到它,我们可以决定“接受”它,并弹出两个列表,或者我们可以决定寻找另一个
HX
,如:

sublist([HX|TX],[HX|TY]) :-
    sublist(TX,TY).
sublist(X,[_|TY]) :-
    X = [_|_],
    sublist(X,TY).
中最后一个子句中的
X=[124; 124;]
不是严格必需的,但是可以防止使用
子列表([],X)
子句生成重复的结果

或者把它放在一起:

list([]).
list([_|T]) :-
    list(T).

sublist([],L) :-
    list(L).
sublist([HX|TX],[HX|TY]) :-
    sublist(TX,TY).
sublist(X,[_|TY]) :-
    X = [_|_],
    sublist(X,TY).
这将产生:

?- sublist(L,[1,2,3]).
L = [] ;
L = [1] ;
L = [1, 2] ;
L = [1, 2, 3] ;
false.
?- sublist(L,[1,2,3]).
L = [] ;
L = [1] ;
L = [1, 2] ;
L = [1, 2, 3] ;
L = [1, 3] ;
L = [2] ;
L = [2, 3] ;
L = [3] ;
false.
或:

或:


您不需要规则
cut(u,[],[124;)]:-false。
如果缺少该规则,将导致类似
cut(,[],[124;)的查询失败,因为它与后续规则不匹配。您是否尝试过进行
跟踪
?或者你只是试着测试
cut/3
本身?您创建
cut/3
而不只是使用
select/3
有什么原因吗?您不需要规则
cut(,[],[124;]):-false。
。这是多余的,因为
cut(u,[],[[uu |)
将由于缺少后续/匹配规则而失败。@潜伏者:实际上根本不需要
cut
。目前我正在写一个更优雅的方法来解决这个问题。但是,如果要定义这样一个
cut/3
,则不需要该子句。此外,ISO序言中已经定义了一个
select/3
。)但是,你确实指出了OP在谓词中的错误,这正是他们所要求的。:)
?- sublist([1,2,3],[1,2,4,5,3,6]).
true ;