2010-10-18 26 views
3

好了,我有這個GNU序言 - 遞歸問題(?易)

edu_less(hs,college). 
edu_less(college,masters). 
edu_less(masters,phd). 

我需要編寫一個函數來告訴如果事情是小於其他。謂詞是

edu_le. 

所以,如果我把edu_le(hs,phd).它應該返回是。 我想出了這個。

edu_le(A,B) :- A = B. 
edu_le(A,B) :- edu_less(A,B). 
edu_le(A,B) :- edu_less(A,C), edu_le(C,B). 

我真的不希望它經歷一切,並返回多個答案。

如果發現它實際上小於或等於第二個參數,是否可以只返回yes或no?

因此,基本上如果我再次使用edu_le(hs,phd)這個例子,那麼因爲hs不到大學,而且大學不是大師,而且大師不到phd,那麼hs必須小於phd,並且會說是。

對不起,對於prolog來說真的很陌生,仍然試圖解決這個問題。

回答

3

寫這樣謂詞的最實用的方法是使用cut(!)。削減導致進一步的條款在回溯時不予考慮。你會寫你的謂詞如下:

edu_le(A,B) :- A = B, !. 
edu_le(A,B) :- edu_less(A,B), !. 
edu_le(A,B) :- edu_less(A,C), edu_le(C,B). 

最後一句話,不需要切割,因爲沒有其他的條款考慮反正。在任何測試之後放置剪切以確定該子句是否應該成功。

邏輯編程純粹主義者不贊成裁減,因爲它使得謂詞的含義取決於子句的排序,這與數學中的邏輯不同。 !

+0

AHHHHHHHH(像聖潔啊)。謝謝。感謝上帝,我不是純粹主義者吧? – Matt 2010-10-18 04:35:02

2

/0也使得這個程序不完整,例如考慮有兩個版本的最普遍的查詢:

?- edu_le(X, Y). 

它往往是更好,如果你只想要一個特別的單身證明使用一次/ 1目標:

?- once(edu_le(hs, phd)). 
3

在謂詞定義

edu_le(A,B) :- A = B. 
edu_le(A,B) :- edu_less(A,B). 
edu_le(A,B) :- edu_less(A,C), edu_le(C,B). 

第二克勞斯e是多餘的並且導致重複產生的答案。使用

edu_le(A,B) :- A = B. 
edu_le(A,B) :- edu_less(A,C), edu_le(C,B). 

這給你一個答案true,則沒有更多的答案(false)上的回溯。您可以在第一個子句中使用剪切,但生成不再有效。

?- edu_le(hs,X). 
X = hs ; 
X = college ; 
X = masters ; 
X = phd ; 
false. 

變得不完全:

?- edu_le(hs,X). 
X = hs. 

由於墊建議,使用once/1代替。在一個很好的Prolog實現中,這個謂詞的作用就好像你的程序在戰略位置上有削減,加速你的程序而不影響其邏輯語義。

1

我建議你不要遵循JuhoÖstman提出的路徑並保持純潔 - 否則,爲什麼要在第一個例子中使用Prolog?如果你堅持邏輯範式太寬大,你會得到一些令人不快的結果。在這種情況下,Juho的謂詞絕對不同於你的,我會告訴你爲什麼。正如larsmans所說,首先,放棄無用的edu_le(A,B) :- edu_less(A,B).規則。你會得到你原來的謂詞的少冗餘版本:

edu_le1(A, A). 
edu_le1(A, B) :- edu_less(A, C), edu_le1(C, B). 

它只是表現爲edu_le,意思是:給定一個任意的查詢,它產生完全一樣的答案,除了重複(edu_le1具有以下)。你可能只是對它感到滿意,但它仍然有一些你可能不喜歡的冗餘答案;例如,SWI下:

?- edu_le1(hs, hs) 
true ; 
false. 

現在你可以說你不喜歡它,因爲它仍然具有冗餘false,但如果你使用的Juho的謂詞代替(沒有無用的規則):

edu_le2(A, A) :- !. 
edu_le2(A, B) :- edu_less(A, C), edu_le2(C, B). 

你消除它是真的沒用的最終false

?- edu_le2(hs, hs) 
true. 

?- 

,但你失去不止於此:你輸了,作爲墊的話,產生的所有次的可能性當一個變量沒有實例化Ê解決方案:

?- edu_le1(hs, B) %same, with more copies, for edu_le 
B = hs ; 
B = college ; 
B = masters ; 
B = phd ; 
false. 

?- edu_le2(hs, B) 
B = hs.   %bad! 

?- 

換句話說,後者謂詞不是相當於前者:edu_leedu_le1具有類型edu_le(?A, ?B),而代替edu_le2具有類型edu_le2(+A, +B)(參見[1]的含義)。請確保:edu_le2不太有用,因爲它的功能較少,因此可以在較少的上下文中重複使用。這是因爲edu_le2中的剪切是一種紅色剪切,即剪切,它改變了引入謂詞的含義。鑑於您瞭解兩者之間的差異,您可能會滿意它。這完全取決於你想用它做什麼。

如果你想獲得最好的兩個世界,你需要在edu_le1中引入一個適當的綠色切割,當A和B被完全實例化時,降低冗餘度。在此目的下,您必須檢查A和B在切割前是否被實例化爲相同的術語。你不能用=來做,因爲=不檢查,但統一。正確的操作是==

edu_le3(A, B) :- (A == B -> ! ; true), A = B. 
edu_le3(A, B) :- edu_less(A, C), edu_le3(C, B). 

注意的是,在第一條規則的附加切口才能處於激活AB碰巧是同一個術語。現在的髮型是一種合適的綠色切,謂語也工作在最一般的情況下,你原來一個:

?- edu_le3(A, A). 
true. 

?- edu_le3(A, B). %note that A and B are not the same term 
A = B ; 
A = hs, 
B = college ; 
A = hs, 
B = masters ; 
A = hs, 
B = phd ; 
A = college, 
B = masters ; 
A = college, 
B = phd ; 
A = masters, 
B = phd ; 
false. 

?- 

與Prolog的通過所有的解決方案回溯。

我不認爲有一種方法可以消除最後的false而不會對edu_lt引入太強的依賴性。這是因爲我們必須保持開放的可能性,以便在後來決定用更多的基礎事實來豐富它時再探索另一個edu_lt。所以,在我看來,這是最好的你可以擁有。

[1] SWI Prolog的參考手冊,第4.1節。