2013-03-28 22 views
0

我有以下事實如何在序言事實遞歸搜索

%exam(Student,Subject) 

exam(student1,subject1). 
exam(student2,subject1). 
exam(student3,subject1). 

exam(student1,subject2). 
exam(student3,subject2). 

exam(student1,subject3). 

我想找到一個學生的科目,並把它們放在一個列表

Subjects(Student,[H|T]):- 
         exam(Student,Subject), 
         \\+Subject=H, 
         H = Subject, 
         Subjects(Student,T). 

我想不出基本情況應該是什麼!

+2

study [findall](http://www.swi-prolog.org/pldoc/doc_for?object=section%282,%274.30%27,swi%28%27/doc/Manual/allsolutions.html%27 %29%29) – CapelliC 2013-03-28 10:25:19

回答

1

\+ Subject = H手段, 「不能證明Subject可以H統一。

但是因爲H開始沒有實際意義,所以它可以始終與Subject統一,以便目標總是失敗。

而且,看其是否Subject先前被發現,你必須檢查其成員在以前發現的值的列表。這意味着,攜帶一個來電呼叫的附加參數,該參數將以[]開頭,在其中添加新發現的主題,並使用更新的列表進行下一個呼叫。

只要你能找到一個新的事實,你將它添加到這個累積列表中,並繼續;但如果你找不到新的事實,你應該停下來。這將是你的基本情況。使用輔助謂詞進行編碼會更容易,每個輔助謂詞執行單獨的任務(如can_find_new_subject(Student, ListSeenSoFar, Subject)等)。

subjects(Student, L):- search_subjects(Student, [], L). 

search_subjects(Student, Seen, L):- 
    find_new_subject(Student, Seen, Subj) 
    search_subjects(Student, [Subj|Seen], L). 

search_subjects(Student, Seen, L):- 
    \+ find_new_subject(Student, Seen, Subj), 
    ... . 

find_new_subject(...... 
    .... 

該設置的缺點是它將是二次的。如果沒有像assert這樣的額外邏輯設施,或者使用內置的findall等,就無法使其達到線性。