3

我正在尝试从 Prolog 的列表中删除第一次出现的元素。

我的代码:

remove_first_X(X,[X|Xs],Xs). %remove X
remove_first_X(X,[Y|Xs],[Y|Xs]) :-
   remove_first_X(X,Xs,Xs).

不起作用:

?- remove_first_X(1,[1,2,3],[2,3]).
true.

?- remove_first_X(1,[2,1,3],[2,3]).
false.

请帮忙!:-)

另一种尝试更接近:

remove_first_X(X,[X|Xs],Xs).
remove_first_X(X,[Y|Xs],[Y|Ys]) :-
   remove_first_X(X,Xs,Ys).

但在第一次出现后删除 X:

?- remove_first_X(1,X,[2,1,0]).
X = [1, 2, 1, 0] ;
X = [2, 1, 1, 0] ;
X = [2, 1, 1, 0] ;
X = [2, 1, 0, 1] ;
false.
4

2 回答 2

4

@chamini2 给出的实现是不纯的,并且在使用非基本术语时可能在逻辑上变得不合理。考虑以下两个查询:

?- E=1 , remove_first_X(E,Xs,[2,1,0])。
E = 1,Xs = [1,2,1,0];
E = 1,Xs = [2,1,1,0];
错误的。

?- remove_first_X(E,Xs,[2,1,0]), E=1。
E = 1,Xs = [1,2,1,0];
错误的。%缺少一种解决方案!

来救援! 通过替换(\=)/2dif/2代码在逻辑上变得纯粹

remove_1st_x(X,[X|Xs],Xs).
remove_1st_x(X,[Y|Xs],[Y|Ys]) :- 
    dif(X,Y),
    remove_1st_x(X,Xs,Ys).

让我们再次运行上面的查询,这次使用改进的实现:

?- E=1 , remove_1st_x(E,Xs,[2,1,0])。
E = 1,Xs = [1,2,1,0];
E = 1,Xs = [2,1,1,0];
错误的。

?- remove_1st_x(E,Xs,[2,1,0]), E=1。
E = 1,Xs = [1,2,1,0];
E = 1,Xs = [2,1,1,0];
错误的。

这样更好!OP 给出的其他查询也可以正常工作:

?- remove_1st_x(1,[1,2,3],[2,3]).
true ;
false.

?- remove_1st_x(1,[2,1,3],[2,3]).
true ;
false.

?- remove_1st_x(1,X,[2,1,0]).
X = [1,2,1,0] ;
X = [2,1,1,0] ;
false.

编辑 2015-05-07

当它可以确定地成功时,上面的实现remove_1st_x/3留下了一个无用的选择点。的同时摆脱这种低效率!

使用if_/3和具体化相等(=)/3(又名equal_truth/3),正如@false在对问题“ Prolog union for AUBUC ”的回答中定义的那样,我们可以这样定义:remove_1st_x/3

remove_1st_x(E,[X|Xs],Ys) :-
   if_(X=E, Xs=Ys, (Ys=[X|Ys0],remove_1st_x(E,Xs,Ys0))).

让我们再次运行上面的查询!请注意,所有成功都是确定性的。

?- remove_1st_x(1,[2,1,3],Ys).
Ys = [2,3].

?- remove_1st_x(1,[2,1,3],[2,3]).
true.

?- remove_1st_x(1,[1,2,3],[2,3]).
true.
于 2015-05-04T15:21:54.837 回答
2

尝试在第二次尝试中添加一件事

remove_first_X(X,[X|Xs],Xs).
remove_first_X(X,[Y|Xs],[Y|Ys]) :- 
    X \= Y,
    remove_first_X(X,Xs,Ys).

您运行的示例中发生的情况是

  • 因为X = [1, 2, 1, 0]它只是尝试了第一个子句remove_first_X
  • 下一个元素是进入第二个子句并再次进入第一个子句,您可以看到没有什么禁止的X = Y,这是您应该确保的。
于 2013-11-05T06:23:11.607 回答