簡體   English   中英

Prolog:以意外順序評估的規則

[英]Prolog: Rules evaluating in an unexpected order

我目前正在開發Prolog程序以從列表中刪除重復項。

這是我的代碼:

makeset([First], [First]). % if only one item in list, the solution is itself.
makeset([First, Second], [First, Second]) :-
   dif(First, Second).
makeset([First, Second], [First]) :-
    First = Second.
% if more than two items in list
makeset([First | Tail], FinalList) :-
   member(First, Tail),
   makeset(Tail, FinalList).
makeset([First | Tail], FinalList) :-
   not(member(First, Tail)),
   makeset(Tail, [First |FinalList]).

但是,當我在包含兩個以上項目的列表上嘗試此操作時,它只返回false。 我跑了一個跟蹤,發現它繼續使用最后兩個規則,即使它在列表中的兩個項目。 為什么是這樣?

示例查詢: makeset([3, 2, 4, 5, 1], X). 我得回假,但它繼續使用最后一條規則進行評估。

編輯:我將規則更改為以下內容,但仍然無法正確評估,因此問題必須與最后一條規則有關。

makeset([First], FinalList) :- 
 FinalList = [First]. % if only one item in list, the solution is itself.
makeset([First, Second], FinalList) :- 
 not(First = Second), FinalList = [First, Second].
makeset([First, Second], FinalList) :- 
 First = Second, FinalList = [First].
% if more than two items in list
makeset([First | Tail], FinalList) :- 
 member(First, Tail), makeset(Tail, FinalList).
makeset([First | Tail], FinalList) :- 
 not(member(First, Tail)), makeset(Tail, [First |FinalList]).

我如何修復最終規則?

凈化你的代碼!

首先。 看來你正在堅持這個世界的純粹一面。 當然,你使用的是dif/2 與其程序對應物相比,它的丑陋兄弟(\\=)/2意味着在這個時間點不可統一,但可能更晚,或者從不,不要問我dif/2謂詞具有純粹的陳述性含義。 它意味着(句法或理論上的)不平等。 這不僅會給你帶來業力和嗜好。 不,它甚至可以幫助您調試程序。 事實上,我們可以使用Prolog來幫助我們找到程序中的問題 - 如果只有你的代碼足夠純粹! 首先,讓我們凈化您的代碼,然后我們可以調試它。

你的代碼中唯一不行的是not(member(First, Tail)) 我將用maplist(dif(First),Tail)替換它maplist(dif(First),Tail) 現在我們有一個純粹的程序。 它像以前一樣失敗了。 首先可能是減少列表的大小。 你真的想要完成那件苦差事嗎? 這是一個更簡單的方法,只適用於純Prolog程序。 我會問:

告訴我所有可以想象的列表,他們的設置是什么。

對, 所有列表 沒有人會被遺忘。

問Prolog!

| ?- length(L,I), makeset(L, X).
I = 1, L = [_A], X = [_A] ? ;
I = 2, L = [_A,_B], X = [_A,_B], prolog:dif(_A,_B) ? ;
I = 2, L = [_A,_A], X = [_A] ? ;
I = 2, L = [_A,_A], X = [_A] ? ...

這開始很糟糕! 首先, I = 0沒有解決方案。 讓我們添加事實makeset([], []) ,然后I = 2就有這種冗余。 您可以刪除規則makeset([First, Second], [First]) :- First = Second. 現在,讓我們再次詢問查詢:

| ?- length(L,I), makeset(L, X).
I = 0, L = [], X = [] ? ;
I = 1, L = [_A], X = [_A] ? ;
I = 2, L = [_A,_B], X = [_A,_B], prolog:dif(_A,_B) ? ;
I = 2, L = [_A,_A], X = [_A] ? ;
I = 3, L = [_A,_A,_B], X = [_A,_B], prolog:dif(_A,_B) ? ;
I = 3, L = [_A,_A,_A], X = [_A] ? ;
I = 3, L = [_A,_B,_A], X = [_B,_A], prolog:dif(_B,_A) ? ;
I = 3, L = [_A,_A,_A], X = [_A] ? ;
I = 4, L = [_A,_A,_A,_B], X = [_A,_B], prolog:dif(_A,_B) ? ...

I in 0..2所有答案現在看來都很完美。 它們包含可以想象的所有列表。 他們全部。 請注意,在一個答案中,再次出現dif/2 ,確保元素不同。

對於I = 3事情變得更加復雜。 一些觀察:

  • X = [_,_,_]沒有答案。 發現錯誤! 事實上,發現最小的bug!

  • L = [_A,_A,_A]有一個多余的答案

我們可以將第一個問題減少到一個目標:

| ?- L = [_,_,_], L = X, makeset(L, X).
no

應該有一個答案。 我們現在可以應用另一種策略:

概括您的代碼

顯然, makeset/2的定義過於專業化。 我現在將嘗試概括它以更好地本地化錯誤。 為此,請將以下內容添加到您的程序中:

:- op(950,fy, [*]).

*_.

通過這種方式,我們可以在目標前添加*以將其刪除。 我們也可以使用注釋,但這是一種更簡潔的方法。 所以我現在要做的是系統地添加* ,然后看看目標是否仍然失敗。 此外,我將一些變量重命名為新名稱( _x ),這相當於進一步概括。 經過一番嘗試,我最終得到:

:- op(950,fy, [*]).
*_.

makeset([], []).
makeset([First], [_xFirst]).
makeset([First, Second], [_xFirst, _xSecond]) :-
   * dif(First, Second).
makeset([First | Tail], FinalList) :-
   * member(First, Tail),
   makeset(Tail, FinalList).
makeset([First | Tail], FinalList) :-
   * maplist(dif(First),Tail),
   makeset(Tail, [_xFirst |FinalList]).

?- L = [_,_,_], L = X, makeset(L, X).

在這個程序中,實際元素不再相關。 因此它只是列表的長度! 所以問題必須與處理長度的方式有關。 如果存在第二個參數為更長列表的解決方案,則最后一條規則僅適用。 哪個不可以。 所以問題是最后一條規則。 列表應該在頭部發生。

現在,出現了新的裁員。 最終定義如下:

makeset([], []).
makeset([First | Tail], FinalList) :-
   member(First, Tail),
   makeset(Tail, FinalList).
makeset([First | Tail], [First|FinalList]) :-
   maplist(dif(First),Tail),
   makeset(Tail, FinalList).

有更聰明的方式來表達這個member / maplist dif二分法。 但我會這樣離開......

在最后一條規則中,您將元素從第一個列表移動到第二個列表。 然后,您將阻止匹配最高規則。

注意:dif / 2它是一個強大但復雜的謂詞。 你有效地需要它的力量嗎?

makeset([First | Tail], [First | FinalList]) :- 
 not(member(First, Tail)), makeset(Tail, FinalList).

您不應該將makeset的輸入的First部分設置為阻止先前的規則匹配。 您應該只添加First后到列表FinalList使用統一makeset謂語。

當輸入列表為空時,您的解決方案也無法處理該情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM