Recursion Prolog中的子列表谓词
我试图在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, !.
子列表(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 ;