2014-04-13 76 views
3

我有更小的子表像的大名單中的每個元素:序言:顯示各子表

[ [005,Chester,100],[001,Bob,99],[002,Andy,77] ] 

我試圖做一個顯示「功能」,通過整個列表,並顯示像循環:

No.1: ID="005", Name="Chester", Grade=100 
No.2: ID="001", Name="Bob", Grade=99 
No.3: ID="002", Name="Andy", Grade=77 

在prolog中思考是很難,但我正在努力與遞歸思維。任何援助非常感謝!

回答

5

剛剛遞歸處理數據結構,我認爲這是Prolog的主要問題。

我們知道知道是適當形狀的數據結構缺乏表達力,它激發了兩個擴展(如B-Prolog中的循環)和語言 - 如Picat

不管怎麼說,純Prolog的是強大到足以解決你的問題:

show_records(L) :- 
    forall(nth1(N, L, E), format('No.~d:ID="~s",Name="~s",Grade="~d"~n', [N|E])). 

產量

?- show_records([ ['005','Chester',100],['001','Bob',99],['002','Andy',77] ]). 
No.1:ID="005",Name="Chester",Grade="100" 
No.2:ID="001",Name="Bob",Grade="99" 
No.3:ID="002",Name="Andy",Grade="77" 
true. 
+1

這是一個非常好的小解決方案。 –

+1

這是一個非常不錯的小解決方案':)' –

+1

謝謝。我不得不改變〜〜以便它能夠在unix中使用我的字符串。在swi-prolog上它完美運行。猜這是因爲我的字符串存儲在單引號? – GeorgeCostanza

0

你不需要遞歸。首先,編寫一個謂詞,通過使用Prolog的format predicate(它是一個printf對等項)來顯示每個條目,並直接將該列表作爲參數傳遞。其次,使用maplist將第一個謂詞映射到列表上。

+1

'MAPLIST/2'也許不會那麼做,因爲OP希望線可以由前綴'號碼:'字段。所以'foldl'(將行號作爲累加器)可能更合適。 –

+0

@gniourf_gniourf我很尷尬地說,我從來沒有真正掌握過'foldl'的實際用法,你會友好地給我一個例子,說明在這種情況下如何使用'foldl'?謝謝! –

+1

@aBathologist我爲你做了個答案! –

1

我的答案是用SWI-Prolog編寫的,關於我提到的任何內置謂詞的詳細信息可以在searching the documentation之前得到。不過,我認爲我所說的一切都適用於其他着名的Prolog實現。如果我錯了,請糾正我。

在Prolog,我們與謂詞而不是功能,(或者,我們只使用返回真值函數)的工作。我將使用以下謂語是指你的例子列表我的Prolog的查詢:

ex([ [005,"Chester",100],[001,"Bob",99],[002,"Andy",77] ]). 

對於寫作格式的文本到標準輸出流,我們將使用謂詞format/2。它的簽名是format(+Format, :Arguments),其中Format是一個包含特殊序列以促進插值的原子。換碼序列以代字號開頭,~,完整菜單可以在SWI-Prolo documentation on format/2中找到。 Arguments是用於替換Format中的序列的序言術語列表。在這個例子中,我們只需要~w,它寫入一個參數並且~n寫入一個換行符。作爲一個普通的例子:例如,

?- format('Write ~w, then ~w, followed by ~w~n~n', ['this', 'that', 'the other']). 
Write this, then that, followed by the other 

true. 

你代表的是一個人的形式[ID, Name, Grade]的列表,所以我們只需要編寫一個斷言,這將讓我們在「No.N」添加N ,然後我們可以使用人次列表的參數其餘format/2

display_person(N, Person) :- 
    format('No.~w: ID="~w", Name="~w", Grade=~w~n', [N|Person]). 

format/2第二個參數,N前綴作爲參數列表的頭部。我們可以這樣測試謂詞:

?- ex([P|Ps]), display_person(1, P). 
No.1: ID="5", Name="Chester", Grade=100 
P = [5, "Chester", 100], 
Ps = [[1, "Bob", 99], [2, "Andy", 77]]. 

這會照顧顯示每個人的個人列表。現在我們只需要遍歷你的人員列表並顯示每個成員。爲了跟蹤N對顯示的'N'部分的增加值,我們需要一個兩位謂詞,但是我們只需要一個謂詞來將列表傳遞給顯示謂詞。這個要求導致我們使用使用由輔助謂詞支持的前端謂詞的常見模式:

display_people(People): - display_people(1,People)。%%初始化具有起始值1

display_people調用display_people/2(_,[])。 display_people(N,[人|人物]): - display_person(N,人), M爲N + 1, display_people(M,人)。

運行使用列表中的測試從ex/1

?- ex(Ps), display_people(Ps). 
No.1: ID="5", Name="Chester", Grade=100 
No.2: ID="1", Name="Bob", Grade=99 
No.3: ID="2", Name="Andy", Grade=77 
Ps = [[5, "Chester", 100], [1, "Bob", 99], [2, "Andy", 77]] ; 
false. 

然而圖案p([X|Xs]) :- q(X), p(Xs)只是maplist/n謂詞是什麼,所以我們可以拯救自己有點打字的,可以說是做聲明的含義該方案通過寫更清楚以下內容:

display_people(People) :- 
    length(People, NumPeople), 
    numlist(1, NumPeople, Nums), 
    maplist(display_person, Nums, People). 

numlist(Low, High, Nums)返回一個列表,Nums,從Low到值。在前述定義中,maplist(display_person, Nums, People)將基本上調用display_person(N, P)用於NumsP和每對NPeople

1

這個答案是唯一的回答aBathologist有關使用foldl。我逐字抄襲他的display_person/2斷言:

display_person(N, Person) :- 
    format('No.~w: ID="~w", Name="~w", Grade=~w~n', [N|Person]). 

這時,一個小的適配器,將在前面的謂詞遞增N(並提出的論點正確的順序):

display_person(Person,N,NextN) :- 
    display_person(N,Person), 
    NextN is N+1. 

並使用foldl

display_people(People) :- 
    foldl(display_person,People,1,_). 

如果

`People=[P1,P2,...,Pn]` 

然後foldl(display_person,People,1,Rn)等同於:

display_person(People,1,R1), 
display_person(People,R1,R2), 
... 
display_person(People,R(n-1),Rn). 

以這種方式使用的foldl避免經歷的名單,一旦得到它的長度。但是,另一方面,您需要一個適配器謂詞。

不管怎樣,在這種情況下,更好或更壞是不是真的很重要! foldl只是另一個很好知道的技巧,有時可以使代碼更清晰。

+1

非常有幫助。我認爲CapelliC的答案只是簡潔和高效的結果,但我非常感謝關於在最終使我的操作清晰的情況下使用'foldl'的教程。我完全錯過了'foldl'的最後兩個參數應該工作的方式,但現在我明白了!正如你所說,它的另一個(我認爲真的很重要?)詭計。非常感謝! –