我试图在Prolog中为列表操作实现一些谓词。 一切都按预期工作。例如
append([],Ys,Ys).
append([X|Xs],Ys,[X|Zs]) :- append(Xs,Ys,Zs).
示例查询:
?- append([1,2,3],[4,5,6],X).
X = [1,2,3,4,5,6]. % OK
但我在'删除' -predicate方面遇到了麻烦。以下是它的实施方式:
delete(X,[Y|Ys],Zs) :- X == Y, delete(X,Ys,Zs).
delete(X,[_X|Ys],[_Z|Zs]) :- delete(X,Ys,Zs).
delete(_X,[],[]).
结果不佳的示例查询:
?- delete(4,[1,2,3,4],X).
X = [_G8975, _G8978, _G8981]. % BAD
我已经使用进一步的输入对其进行了测试,它总是返回预期长度的列表,以便它的工作方式。但为什么我只得到那些神秘的_GXXXX而不是数字?
非常感谢提前!
答案 0 :(得分:4)
您的计划中有几个问题。但首先,作为初学者:
在您的程序中,您正在使用不再位于该纯子集中的(==)/2
。在您的情况下,请将其替换为(=)/2
。
Prolog的顶级循环只显示第一个答案。您必须按; 或 SPACE 来要求更多。您的程序(=)/2
给出(更可读的变量):
?- delete(4,[1,2,3,4],X).
X = [_A,_B,_C] ;
X = [_A,_B,_C,_D] ;
false.
即:第一个答案不仅意外,而且还有第二个答案,其长度与原始答案相同。另一方面,第一个答案包括预期的解决方案。所以该计划过于笼统。
?- delete(4,[4],L).
L = [] ;
L = [_A] ;
false.
第一个答案似乎现在正确,但第二个答案完全出乎意料。也就是说,delete(4,[4],[any])
要本地化该计划,请尽可能通过引入 false
和 =
等目标来专门化该计划,并且只要delete(4,[4],[any])
成功。我想出来了:
?- delete(4,[4],[any]).delete(X,[Y|Ys],Zs) :- false, X = Y, delete(X,Ys,Zs). delete(X,[_X|Ys],[_Z|Zs]) :- X = 4, _X = 4, _Z = any, delete(X,Ys,Zs). delete(_X,[],[]) :- _X = 4.
现在显而易见的是,在此规则中,_X =4, _Z = any
应该相同,X = 4, _X = 4
应该是不同的。不平等最好用dif/2
表示。
delete(_X, [], []).
delete(X, [Y|Ys], [Y|Zs]) :-
dif(X, Y),
delete(X, Ys, Zs).
delete(X, [X|Ys], Zs) :-
delete(X, Ys, Zs).
现在可以通过多种方式使用此定义。像
?- delete(X,Xs,[1,2,3]).
Xs = [1, 2, 3],
dif(X, 3),
dif(X, 2),
dif(X, 1) ;
Xs = [1, 2, 3, X],
dif(X, 3),
dif(X, 2),
dif(X, 1) ;
Xs = [1, 2, 3, X, X],
dif(X, 3),
dif(X, 2),
dif(X, 1) ...
请注意,现在有无限多的答案!
答案 1 :(得分:4)
这个答案的灵感来自逻辑纯代码 @false提出in his answer。
让我们使用元谓词tfilter/3
和术语不等式dif/3
并简单地写:
?- Vs0 = [1,2,3,4], tfilter(dif(4),Vs0,Vs). Vs0 = [1,2,3,4], Vs = [1,2,3 ]. % succeeds deterministically ?- Vs0 = [1,2,3,4,2,3,4], tfilter(dif(2),Vs0,Vs). Vs0 = [1,2,3,4,2,3,4], Vs = [1, 3,4, 3,4]. % succeeds deterministically
delete/3
的实施归结为:
delete(E,Vs0,Vs) :-
tfilter(dif(E),Vs0,Vs).
与@ false的代码一样,此实现是单调,这使得谓词具有多样性,使您能够获得逻辑上合理的答案 即使在处理非基础条款时也是如此。
最后,让我们有一个非常一般的查询并查看所有答案:
?- Vs0 = [X,Y,Z], delete(E,Vs0,Vs). Vs0 = [X,Y,Z], E=X , E=Y , E=Z , Vs = [ ] ; Vs0 = [X,Y,Z], E=X , E=Y , dif(E,Z), Vs = [ Z] ; Vs0 = [X,Y,Z], E=X , dif(E,Y), E=Z , Vs = [ Y ] ; Vs0 = [X,Y,Z], E=X , dif(E,Y), dif(E,Z), Vs = [ Y,Z] ; Vs0 = [X,Y,Z], dif(E,X), E=Y , E=Z , Vs = [X ] ; Vs0 = [X,Y,Z], dif(E,X), E=Y , dif(E,Z), Vs = [X, Z] ; Vs0 = [X,Y,Z], dif(E,X), dif(E,Y), E=Z , Vs = [X,Y ] ; Vs0 = [X,Y,Z], dif(E,X), dif(E,Y), dif(E,Z), Vs = [X,Y,Z].
答案 2 :(得分:2)
摆脱神秘变量名称的一种神秘方式是使用numbervars/3
,例如,
?- length(X, 3).
X = [_G2019, _G2022, _G2025].
?- length(X, 3), numbervars(X, 0, _).
X = [A, B, C].
现在转到delete/3
。除了其他小问题,如参数的异常顺序,子句的异常顺序等,你有一个主要问题:在第二个子句中,你将一个新的匿名变量放在原始列表的元素应该是的位置。
delete(X, [Y|Ys], [Y|Zs]) :- delete(X, Ys, Zs).
在第二个条款中,它有点有效:
?- delete(4, [1,2,3,4], L).
L = [1, 2, 3] .
?- delete(2, [1,2,3,4,2,3,4], L).
L = [1, 3, 4, 3, 4] .
您的实施还存在其他问题。您可以在SWI-Prolog的library(lists)
中查看同一谓词的implementation:阅读文档!