我试图创建一个能够从列表中删除所有元素的函数。我看到一些解决方案已经mentioned。但我尝试了不同的方法。 我基本上是在复制新列表中的元素,如果它们不等于我想要删除的内容。
remove(X, [], A, A):-!.
remove(X1, [X1|T1], A, R):-
remove(X1, T1, A, R).
remove(X2, [H2|T2], A2, R2):-
remove(X2, T2, [H2 |A2], R2).
第一个答案是我期望的结果,但随后它不断提供更多可能性:
?- remove(x, [x, b,c,x,x], [], Result).
Result = [c, b] ;
Result = [x, c, b] ;
Result = [x, c, b] ;
Result = [x, x, c, b] ;
Result = [c, b, x] ;
Result = [x, c, b, x] ;
Result = [x, c, b, x] ;
Result = [x, x, c, b, x].
编辑:我也意识到这也是在逆转我的名单:(
答案 0 :(得分:4)
问题在于条款:
remove(X2, [H2|T2], A2, R2):-
remove(X2, T2, [H2 |A2], R2).
您需要明确说明X2
与H2
不同。您可以使用dif/2
:
remove(X2, [H2|T2], A2, R2):-
dif(X2,H2),
remove(X2, T2, [H2 |A2], R2).
如果你没有声明X2
,H2
是不同的,Prolog会尝试两种情况,这会导致保留或抛出元素H2。
答案 1 :(得分:3)
简短回答:如果你写remove(X2, [H2|T2], A2, R2)
,这并不意味着X2
和H2
不同,所以你需要阻止Prolog采取这种做法科。 Prolog的一个基本方面是它自动执行回溯。因此,一个条款“触发”的事实并不妨碍它从其他条款中解除。
快速修复可以为第二个子句添加剪切:
remove(X, [], A, A) :-
!.
remove(X1, [X1|T1], A, R):-
!, % a cut
remove(X1, T1, A, R).
remove(X2, [H2|T2], A2, R2):-
remove(X2, T2, [H2 |A2], R2).
因此,如果X2
和H2
可以统一,Prolog将采用第二个条款,然后剪切将阻止Prolog采用第三个条款。
另一个重要方面是您的程序撤消列表。我们可以通过在这里删除累加器来解决这个问题(你也可以使用差异列表作为累加器,但这会引入太多的复杂性):
remove(_, [], []).
remove(X1, [X1|T1], R):-
!,
remove(X1, T1, R).
remove(X2, [H2|T2], [H2|R2]):-
remove(X2, T2, R2).
现在你可以用它来删除可能相同的列表中的元素:注意Prolog执行统一,所以它也会删除自由变量,或部分未接地的可以统一。
但是:削减是危险的,通常会导致不纯的谓词。 Prolog的想法是您可以在多个方向中使用谓词。例如,您可以生成所有可能的列表,以便删除3
后的结果为[1,4,2,5]
。为此,我们可以添加约束dif/2
:
remove(_, [], []).
remove(X2, [H2|T2], [H2|R2]) :-
dif(X2, H2),
remove(X2, T2, R2).
remove(X1, [X1|T1], R):-
remove(X1, T1, R).
我们也在这里删除了剪切。
现在我们可以使用不同的任务查询它:
从列表4
中删除所有[1,4,2,4,4,5]
:
?- remove(4,[1,4,2,4,4,5],X).
X = [1, 2, 5] ;
false.
从列表中删除 元素A
:
?- remove(A,[1,4,2,4,4,5],X).
X = [1, 4, 2, 4, 4, 5],
dif(A, 5),
dif(A, 4),
dif(A, 4),
dif(A, 2),
dif(A, 4),
dif(A, 1) ;
A = 5,
X = [1, 4, 2, 4, 4] ;
A = 2,
X = [1, 4, 4, 4, 5] ;
A = 4,
X = [1, 2, 5] ;
A = 1,
X = [4, 2, 4, 4, 5] ;
false.
生成所有可能是删除输入的列表,结果为[1,4,2,5]
(无限量的答案):
?- remove(A,L,[1,4,2,5]).
L = [1, 4, 2, 5],
dif(A, 5),
dif(A, 2),
dif(A, 4),
dif(A, 1) ;
L = [1, 4, 2, 5, A],
dif(A, 5),
dif(A, 2),
dif(A, 4),
dif(A, 1) ;
L = [1, 4, 2, 5, A, A],
dif(A, 5),
dif(A, 2),
dif(A, 4),
dif(A, 1) ;
L = [1, 4, 2, 5, A, A, A],
dif(A, 5),
dif(A, 2),
dif(A, 4),
dif(A, 1) ;
L = [1, 4, 2, 5, A, A, A, A],
dif(A, 5),
dif(A, 2),
dif(A, 4),
dif(A, 1)
...
从列表中删除了哪些元素?
?- remove(A,[1,4,3,2,5],[1,4,2,5]).
A = 3 ;
false.
?- remove(A,[1,3,4,3,2,5],[1,4,2,5]).
A = 3 ;
false.
我们可以从[1,4,2,5]
中仅删除一种值来获取列表[1,9,4,3,2,5]
吗? (不!)
?- remove(A,[1,9,4,3,2,5],[1,4,2,5]).
false.