2010-11-21 140 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