(这不是一个课程问题.只是我个人的学习.)
我正在尝试在Prolog中进行练习以从列表中删除元素.这是我的代码:
deleteall([],X,[]).
deleteall([H|T],X,Result) :-
H==X,
deleteall(T,X,Result).
deleteall([H|T],X,[H|Result]) :- deleteall(T,X,Result).
Run Code Online (Sandbox Code Playgroud)
当我测试它时,我首先得到一个很好的答案(即删除了所有的X.)然后回溯为我提供了列表的所有其他变体,其中删除了一些或没有X的实例.
为什么会这样?为什么H == X的情况会落到最后一个子句?
在Prolog中,如果你这样写:
delete([(1,1),(1,2),(1,1),(3,4)],(1,_),L).
Run Code Online (Sandbox Code Playgroud)
结果将是:
L = [ (1, 2), (3, 4)].
Run Code Online (Sandbox Code Playgroud)
什么是正常的,因为_变量在第一个元素中与1绑定,它搜索(1,1)的其他元素并删除它们.
有没有办法阻止这种统一发生并删除表格的所有成员(1,_).在这种情况下,结果必须是:L = [(3,4)].
我需要在列表中找到第一个重复值.
prep(3,[1,3,5,3,5]). 应该是真的.
prep(5,[1,3,5,3,5]). 应该是假的.
我想检查与当前值和先前列表成员的相等性,直到我找到重复,如果它找到一个它将测试与X的相等但我不知道如何在Prolog中做到这一点!
我感谢任何帮助!谢谢
:- use_module(library(clpfd)).
fact(treated=A) :- A in 0..1.
fact(numYears=B) :- B in 0..sup.
fact(numDrugs=C) :- C in 0..sup.
fact(treated2=D) :- D in 0..1.
fact(cParam=E) :- E in 0..4.
is_differentfact(X,X) :- false.
is_differentfact(Element=_,OtherElement=_) :-
dif(Element,OtherElement).
is_fakt([]).
is_fakt([X|Xs]) :-
fact(X),
maplist(is_differentfact(X),Xs),
is_fakt(Xs).
Run Code Online (Sandbox Code Playgroud)
为什么?- is_fakt(X)返回一个结果列表的答案,但在一些结果答案后它会挂起.我不知道为什么Prolog无法返回X的所有可能值.
我有一个列表[a, b, a, a, a, c, c]
,我需要再添加两个元素.
最终结果应如下所示:
[a, a, a, b, b, b, a, a, a, a, a, c, c, c, c]
Run Code Online (Sandbox Code Playgroud)
如果我在列表中有一个与下一个项目相同的项目,那么它会继续运行,直到有一个新项目,当它找到新项目时,它会添加前一项目的两次,然后继续.
这是我的代码到目前为止,但我无法弄清楚如何添加两个...
dbl([], []).
dbl([X], [X,X]).
dbl([H|T], [H,H|T], [H,H|R]) :- dbl(T, R).
Run Code Online (Sandbox Code Playgroud) 所以我试图在prolog中编写一个谓词,它可以获取列表L1和列表L2,并返回L1中不在L2中的所有元素的列表.这是我到目前为止:
% Append an element to a list.
myappendelem(X,L,[X|L]).
% True if input list contains X.
mycontains([H | T], X) :-
H == X;
mycontains(T,X).
% Does the work for notin().
nocontains([],_,A,A).
nocontains([H|T],L,A,R):-
mycontains(L,H),
nocontains(T,L,A,R);
myappendelem(H,A,AR),
nocontains(T,L,AR,R).
% Returns all elements in L1 not in L2.
notin(L1,L2,R):-
nocontains(L1,L2,[],X).
Run Code Online (Sandbox Code Playgroud)
这有效,但它提供了多个答案,例如:
notin([5,1],[4,3,2,1],X).
X = [5];
X = [5,1].
Run Code Online (Sandbox Code Playgroud)
这是一个问题,因为我使用这个谓词来排序图中的路径(L1是我可能去的节点列表,L2是我已经去过的节点)以确保我不会访问同一个节点不止一次,陷入困境.但是这个实现让我陷入了一个循环,因为它在尝试第一个X之后回溯并且它失败了,对于未改变的X,进入可以相互到达的相同两个节点之间的无限循环.我知道通过向nocontains添加切割就可以轻松解决这个问题:
% Does the work for notin().
nocontains([],_,A,A).
nocontains([H|T],L,A,R):-
mycontains(L,H),!,
nocontains(T,L,A,R);
myappendelem(H,A,AR),!,
nocontains(T,L,AR,R).
Run Code Online (Sandbox Code Playgroud)
但有没有办法在没有削减的情况下实现同样的目标?所以,当我使用notin时,我只得到一个可能的答案?(它用于学校,部分任务是不使用任何内置谓词或控制操作符)
编辑:
只是为了更具体地说明赋值的局限性:它应该由纯粹的事实和规则组成,我们不允许使用任何内置的谓词或控制结构(包括但不限于算术,削减或否定 - 失败).分号没问题.我们需要定义自己的任何实用程序谓词.
感谢所有的答案,但我开始认为这可能是我用于在图中的两个节点之间找到路径的方法的一个问题,因为从答案看起来不是很简单的方法这个.
TL;DR: sibling(a,X)成功回答X = a,但sibling(a,a)失败。
我有以下 Prolog 文件:
children(a, c).
children(a, d).
children(b, c).
children(b, d).
sibling(X, Y) :-
X \== Y, A \== B,
children(X, A), children(X, B),
children(Y, A), children(Y, B).
Run Code Online (Sandbox Code Playgroud)
对我来说似乎很清楚,如果他们的父母相同,那么两个人就是兄弟姐妹。此外,一个人不是他们自己的兄弟姐妹。
但是当我尝试在 GNU Prolog 上运行一些查询时,我得到了一些奇怪的结果:
| ?- sibling(a, b).
true ? a
true
true
yes
Run Code Online (Sandbox Code Playgroud)
这是预期的行为。a并且b是兄弟姐妹。有三个结果,这有点奇怪,但我认为 Prolog 是绑定A = c, B = d和A = d, B = c.
| ?- sibling(a, a).
no
Run Code Online (Sandbox Code Playgroud)
我认为这意味着a …
假设我有一个谓词foo/2,它定义了它的第一个和第二个参数之间的关系.
改变这种实现的最惯用和最有效的方法是什么foo/2:
如果它的两个参数都是基础的,它就像以前一样(如果关系成立则成功,否则失败).
如果两个参数中的一个(或两个)都是空闲的,它会"约束"这两个参数,这样当它们接地时,将检查关系.
换句话说,如何正确地实现由dif/2任何类型的用户定义关系表现出来的行为?
listing(dif/2). 没什么帮助.
如何实现not_all_equal/1谓词,如果给定列表包含至少2个不同的元素,则谓词成功,否则失败?
这是我的尝试(不是很纯粹):
not_all_equal(L) :-
( member(H1, L), member(H2, L), H1 \= H2 -> true
; list_to_set(L, S),
not_all_equal_(S)
).
not_all_equal_([H|T]) :-
( member(H1, T), dif(H, H1)
; not_all_equal_(T)
).
Run Code Online (Sandbox Code Playgroud)
然而,这并不总是具有最佳行为:
?- not_all_equal([A,B,C]), A = a, B = b.
A = a,
B = b ;
A = a,
B = b,
dif(a, C) ;
A = a,
B = b,
dif(b, C) ;
false.
Run Code Online (Sandbox Code Playgroud)
在这个例子中,只有第一个答案应该出来,另外两个答案是多余的.
是否存在差异检查?这在这里有效:
Welcome to SWI-Prolog (threaded, 64 bits, version 8.3.7)
?- set_prolog_flag(occurs_check, true).
true.
?- dif(X,f(Y)), X = Y.
X = Y.
Run Code Online (Sandbox Code Playgroud)
但以上是不可行的,因为发生检查是一个全局标志,我得到以下信息:
SWI-Prolog console for thread 3
?- X=f(X).
false.
Run Code Online (Sandbox Code Playgroud) prolog ×10
prolog-dif ×10
list ×4
backtracking ×1
clpfd ×1
occurs-check ×1
predicate ×1
unification ×1