所以我试图在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时,我只得到一个可能的答案?(它用于学校,部分任务是不使用任何内置谓词或控制操作符)
编辑:
只是为了更具体地说明赋值的局限性:它应该由纯粹的事实和规则组成,我们不允许使用任何内置的谓词或控制结构(包括但不限于算术,削减或否定 - 失败).分号没问题.我们需要定义自己的任何实用程序谓词.
感谢所有的答案,但我开始认为这可能是我用于在图中的两个节点之间找到路径的方法的一个问题,因为从答案看起来不是很简单的方法这个.
这是第一个观察:
?- is_list([]), is_list([_,_,_]).
true.
Run Code Online (Sandbox Code Playgroud)
这是另一个观察:
?- [] = _, [_,_,_] = _.
true.
Run Code Online (Sandbox Code Playgroud)
因此,为什么会is_list/1这样实施
?- is_list(_).
false.
Run Code Online (Sandbox Code Playgroud)
要么
?- is_list([_|_]).
false.
Run Code Online (Sandbox Code Playgroud)
何时_可以清楚地统一列表?这不是逻辑上更健全的true吗?
在SWI-Prolog的文档中is_list/1,注释说:
在5.0.1之前的版本中,
is_list/1只检查[]或[_|_]与proper_list/1有电流的作用is_list/1.目前的定义符合事实上的标准.
为什么这是事实上的标准?
我开始学习Prolog的,我想给定一个整数程序P给予整数A和B这样P = A² + B².如果没有的价值A和B满足这个方程,false应退还
例如:if P = 5,它应该给A = 1和B = 2(或A = 2和B = 1)因为1² + 2² = 5.
我以为这应该工作:
giveSum(P, A, B) :- integer(A), integer(B), integer(P), P is A*A + B*B.
Run Code Online (Sandbox Code Playgroud)
查询:
giveSum(5, A, B).
Run Code Online (Sandbox Code Playgroud)
但事实并非如此.我该怎么办?我对Prolog很新,所以我仍然犯了很多错误.
提前致谢!
如何实现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)
在这个例子中,只有第一个答案应该出来,另外两个答案是多余的.
正如另一个我似乎无法找到的StackOverflow答案所述,这种模式在实际的Prolog代码中经常出现:
pred(X) :-
guard(X),
...
pred(X) :-
\+ guard(X),
...
Run Code Online (Sandbox Code Playgroud)
许多人试图将其浓缩
pred(X) :-
(guard(X) ->
...
;
...).
Run Code Online (Sandbox Code Playgroud)
但是众所周知,箭头结构会破坏选择点并且不符合逻辑.
在Ulrich Neumerkel和Stefan Kral的Indexing dif/2中,if_/3提出了一个单调且合乎逻辑的谓词,然而在论文中他们提到了另一个引起我注意的结构:*->.
该*->构造的功能与上面的unsugared guard子句完全相同,因此它似乎非常适合我的用途,因为我不希望有一个必需的具体条件,if_/3而且我不太关心额外的选择点.如果我没有弄错(编辑:我),它提供了相同的语义,if_/3但没有要求在条件谓词中添加"具体化".
然而,在它的SWI文档中,它声称"这种构造很少使用",这对我来说似乎很奇怪.*->在我看来,它比->你在尝试进行纯逻辑编程时更好.有没有理由避免这种结构,或者是否有更好的替代整个保护条款/否定保护条款模式?
if-statement prolog control-structure implication logical-purity
假设我想断言三个列表的长度相同.我可以这样做:
same_length(First, Second, Third) :-
same_length(First, Second),
same_length(Second, Third).
Run Code Online (Sandbox Code Playgroud)
无论是实例化First还是Second实例化,这都是正确的.当所有三个参数都被实例化时它也可以工作!但是,一个调用length(Third, 3), same_length(First, Second, Third)会使它返回正确答案(所有三个列表的长度为3)和一个选择点,然后循环永远生成永远不会匹配的解决方案.
我写过一个版本,我认为在任何情况下都是正确的:
same_length(First, Second, Third) :-
/* naively calling same_length(First, Second), same_length(Second, Third) doesn't work,
because it will fail to terminate in the case where both First and Second are
uninstantiated.
by always giving the first same_length/2 clause a real list we prevent it from
generating infinite solutions */
( is_list(First), same_length(First, Second), same_length(First, Third), !
; is_list(Second), same_length(Second, First), same_length(Second, …Run Code Online (Sandbox Code Playgroud) 我发布了下面的代码作为这个问题的答案,用户“重复”回答并评论说它在逻辑上不纯粹,“如果您有兴趣对代码进行最小的更改以使其保持逻辑纯度,我建议发布一个新的关于这个问题。我很乐意回答:) “。
% minset_one(1 in D1, 1 in D2, D1, D2, D1Len, D2Len, T).
minset_one_(true, false, D1, _, _, _, D1).
minset_one_(false, true, _, D2, _, _, D2).
minset_one_(true, true, _, D2, D1Len, D2Len, D2) :- D1Len >= D2Len.
minset_one_(true, true, D1, _, D1Len, D2Len, D1) :- D1Len < D2Len.
minset_one(D1, D2, T) :-
(member(1, D1) -> D1check = true ; D1check = false),
(member(1, D2) -> D2check = true ; D2check = false),
length(D1, …Run Code Online (Sandbox Code Playgroud) 消除列表元素的连续重复.
我的解决方案是:
compress([X,X|Xs], Q) :-
compress([X|Xs], Q).
compress([X,Y|Xs], Q) :-
X \= Y,
compress([Y|Xs], QR),
append([X], QR, Q).
compress([X|[]], Q) :-
compress([], QR),
append([X], QR, Q).
compress([], []).
Run Code Online (Sandbox Code Playgroud)
并且,由于我是初学者并且我没有逻辑范例的经验,我请求您说出我可以改进的内容以及为什么我的解决方案不尽如人意.
例如,X \= Y对我来说并不漂亮.
我正在七周的七种语言中工作,但有一些我对prolog不了解.我有以下程序(基于他们的华莱士和grommit程序):
/* teams.pl */
onTeam(a, aTeam).
onTeam(b, aTeam).
onTeam(b, superTeam).
onTeam(c, superTeam).
teamMate(X, Y) :- \+(X = Y), onTeam(X, Z), onTeam(Y, Z).
Run Code Online (Sandbox Code Playgroud)
并像这样加载它
?- ['teams.pl'].
true.
Run Code Online (Sandbox Code Playgroud)
但它没有给我任何解决方案
?- teamMate(a, X).
false.
Run Code Online (Sandbox Code Playgroud)
它可以解决更简单的东西(在书中显示):
?- onTeam(b, X).
X = aTeam ;
X = superTeam.
Run Code Online (Sandbox Code Playgroud)
有解决方案:
?- teamMate(a, b).
true ;
false.
Run Code Online (Sandbox Code Playgroud)
我错过了什么?我尝试了gnu prolog和swipl.
......还有更多......
当你移动"不能成为你自己的队友"的限制然后结束:
/* teams.pl */
onTeam(a, aTeam).
onTeam(b, aTeam).
onTeam(b, superTeam).
onTeam(c, superTeam).
teamMate(X, Y) :- onTeam(X, Z), onTeam(Y, Z), \+(X = Y).
Run Code Online (Sandbox Code Playgroud)
它给了我期望的解决方案:
?- ['teams.pl'].
true. …Run Code Online (Sandbox Code Playgroud) prolog ×9
prolog-dif ×4
list ×3
backtracking ×1
clpfd ×1
if-statement ×1
implication ×1
numbers ×1
predicate ×1
unification ×1