2013-04-21 60 views
0

我想要得到一個謂詞來從1個事實與另一個事實進行關聯,並繼續前進,直到指定的停止點。沒有列表的Prolog關係跟蹤

例如, 假設我正在做一個物流記錄,我想知道誰從誰那裏得到了包裹,他們從哪裏得到它,直到最後。

Prolog的

mailRoom(m). 

    gotFrom(annie,brock). 
    gotFrom(brock,cara). 
    gotFrom(cara,daniel). 
    gotFrom(daniel,m). 


    gotFrom(X,Y) :- gotFrom(Y,_). 

所以我試圖用謂詞gotFrom做的就是它永遠指向你開始遞歸下降從列表(例如:gotFrom(布洛克,誰))和到達由m指定的末端,這是郵件室。

不幸的是,當我運行這個謂詞,它讀出來,

Who = annie. 
    Who = brock. 
    Who = cara. 
    etc.etc.... 

我試圖通過整個事情,但林不知道哪裏來的布洛克去安妮步進,卡拉一路下來,直到它通過trues循環無限。我有一種感覺,它與函數(_)中的通配符有關,但我不知道該如何表達該函數的這一部分,以便謂詞在程序中搜索下一個事實,而不是跳到最後。

我試過在我的程序中使用反切(!),但它給了我同樣的錯誤。

任何幫助,非常感謝。我不想要代碼我只想知道我做錯了什麼,所以我可以學習如何做對。

謝謝。

回答

1

恐怕這個規則是沒有意義的:

gotFrom(X,Y) :- gotFrom(Y,_). 

這裏沒有什麼約束X或Y任何特定的值。此外,單身變量X和匿名變量_的存在意味着基本上任何事情都會起作用。試試看:

?- gotFrom([1,2,3], dogbert). 
true ; 
true ; 

我想你在這裏試圖建立的是某種傳遞屬性。在這種情況下,你想要的是可能更是這樣的:

gotFrom(X,Z) :- gotFrom(X, Y), gotFrom(Y, Z). 

這將產生一個有趣的結果:

?- gotFrom(brock, Who). 
Who = cara ; 
Who = daniel ; 
Who = m ; 
ERROR: Out of local stack 

的原因問題可能不會立即明顯。這是在該規則中發生了兩次未經檢查的遞歸。我們遞歸地統一gotFrom/2然後我們遞歸地統一它。最好將它分解爲兩個謂詞,以便其中一個可以非遞歸方式使用。

got_directly_from(annie,brock). 
got_directly_from(brock,cara). 
got_directly_from(cara,daniel). 
got_directly_from(daniel,m). 

gotFrom(X,Y) :- got_directly_from(X, Y). 
gotFrom(X,Z) :- got_directly_from(X, Y), gotFrom(Y, Z). 

這給了我們所期望的行爲:

?- gotFrom(brock, Who). 
Who = cara ; 
Who = daniel ; 
Who = m ; 
false. 

注意這個人是彈性的,以我的無意義的數據的攻擊:

?- gotFrom([1,2,3], dogbert). 
false. 

一些普遍性的建議:

  1. 永遠不要忽略單身變量警告。他們幾乎總是一個錯誤。
  2. 當你不明白髮生了什麼事情時,千萬不要引入剪切。只有當你首先了解行爲並且你明白剪輯如何影響剪輯時才應該使用剪輯。理想情況下,您應該嘗試將自己限制爲僅影響效果並且沒有可觀察效果的綠色切割。如果你不明白Prolog是做什麼的,那麼添加一個紅色的部分會讓你的問題更加複雜。
+0

我明白了。謝謝丹尼爾,我真的很感謝你們給予的偉大之旅。我被掛在_通配符運算符的想法上,無法想象它過去,但你的解釋讓我超越了它。所以謝謝。我將繼續致力於Prolog的理解。 – user2020331 2013-04-22 20:16:44

+0

@ user2020331太好了,歡迎您!我希望你喜歡使用Prolog並堅持下去。這是一條艱難的道路,但它是值得的! – 2013-04-22 20:21:47