2010-11-21 60 views
4

使用SWI Prolog,有一個謂詞可以找到名爲nth1的列表中的第n個項目。我想實現我自己的謂詞版本,但是如果您查看列表(第nth1)代碼,SWI會非常複雜。有沒有更簡單的方法呢?Prolog中的簡單nth1謂詞

謝謝:)。

+0

澄清你所說的「簡單」?更少的代碼行?您可以移除例如「列表:nth0_det(3,[_,_,_,A | _],A): - !。」否則,簡單化的唯一方法是使其不那麼一般。這是你想要的嗎? – Kaarel 2010-11-21 20:57:02

回答

2

的SWI代碼是有點複雜,因爲謂詞可以用來從一個變量指標產生:

?- nth1(Idx,[a,b,c],X). 
Idx = 1, 
X = a ; 
Idx = 2, 
X = b ; 
Idx = 3, 
X = c ; 
false. 

如果你不希望這樣的行爲,nth1/3可以很容易地在nth0方面實現的:

nth1(Idx,List,X) :- 
    Idx0 is Idx-1, 
    nth0(Idx0,List,X). 

編輯:它也可以在短短的幾行代碼,而不nth0做:

nth1(1,[X|_],X) :- !. 
nth1(Idx,[_|List],X) :- 
    Idx > 1, 
    Idx1 is Idx-1, 
    nth1(Idx1,List,X). 
+0

謝謝larsmans,我不想使用任何第n個謂詞,我已經發布了我的解決方案,您怎麼看?感謝這篇文章。 – ale 2010-11-21 12:35:36

+0

@shuyin,我也發佈了一個'nnth0'的解決方案。 – 2010-11-21 14:40:45

2

我不是故意矛盾或者讓別人來做我的工作,我只是想要一些建議,抱歉不清楚。

我已經自己實現它,但你們可能會建議改進或更好的方法嗎?我經常在Prolog中發現自己正在寫一個謂詞,用一個計數器或一組計數器來得到一個謂詞,用較少的參數來調用具有額外參數的子句。這通常會導致生成相當多的代碼。無論如何,這是我剛纔的實現:

item_at(N, L, Item) :- 
    item_at(N, 0, L, Item). 
item_at(N, Count, [H|_], Item) :- 
    CountNew is Count + 1, 
    CountNew = N, 
    Item = H. 
item_at(N, Count, [_|T], Item) :- 
    CountNew is Count + 1, 
    item_at(N, CountNew, T, Item). 

有什麼意見?謝謝 :)。用法:

?- item_at(3,[a,b,c,d,e],Item). 
Item = c ; 
+0

+1,這個版本是相當一般的(儘管它可能會在回溯/生成時進入無限遞歸)。一個建議,第二個條款可以更短:'item_at(N,Count,[H | _],H): - N是Count +1 1. – 2010-11-21 14:44:15

+0

謝謝larsmans,這是一個很好的改進,非常感謝: )。測試和工作,我可以看到如何:)。 – ale 2010-11-21 15:07:46

4

考慮使用有限域約束一般(可逆)整數運算:

:- use_module(library(clpfd)). 

nth1(1, [E|_], E). 
nth1(N, [_|Xs], E) :- 
     N #> 1, 
     N #= N1 + 1, 
     nth1(N1, Xs, E). 
+0

這與shuyin的解決方案有相同的無限遞歸問題,效率不高。 +1雖然優雅。 (但是,爲了提高效率,我會添加一個約束'N#> 1',並且可能需要剪切。) – 2010-11-21 15:52:20

+1

是的,將N#> 1添加到第二個子句中是個好主意,我認爲這會消除無限遞歸意思是說,即對於像? - nth1(3,Es,X)這樣的查詢?但是,如果在第一個子句中添加一個剪切,將會消除有效的解決方案,例如對於最一般的查詢? - nth1(N,Ls,E),從而使謂詞不完整。 – mat 2010-11-21 17:08:12

+0

你是對的。 – 2010-11-22 10:41:03