List 在SWI-prolog中实现nth1列表操作
您将如何在Prolog中编写自己的谓词,以完全实现nth1函数的功能 对于那些不熟悉该功能的人,最好通过一个示例来显示其功能: ?-nth1(2[a,b,c],E,R) E=b R=[a,c] 调用并传递nth1函数时,将执行以下操作: -要从列表中删除的元素的索引(注意,它不是零索引,这里我们传递的是索引2) -列表(在本例中,它是[a,b,c]) -E,将为其分配从列表中删除的元素 -一个新的列表,它将保存新的列表,减去被删除的元素 我不知该如何开始。如有任何建议,将不胜感激。我知道在SWI Prolog中使用3或4行递归应该是可行的,我只是不知道从哪里开始。这基本上可以给你答案。为了让你开始,考虑你的基本情况,应该是List 在SWI-prolog中实现nth1列表操作,list,prolog,predicate,List,Prolog,Predicate,您将如何在Prolog中编写自己的谓词,以完全实现nth1函数的功能 对于那些不熟悉该功能的人,最好通过一个示例来显示其功能: ?-nth1(2[a,b,c],E,R) E=b R=[a,c] 调用并传递nth1函数时,将执行以下操作: -要从列表中删除的元素的索引(注意,它不是零索引,这里我们传递的是索引2) -列表(在本例中,它是[a,b,c]) -E,将为其分配从列表中删除的元素 -一个新的列表,它将保存新的列表,减去被删除的元素 我不知该如何开始。如有任何建议,将不胜感激。我知道在SWI
nth1(1, [E|R], E, R).
现在,你如何通过递归这个想法来编写其他案例?实际上,这只是掌握Prolog列表语法的窍门。建议在swi Prolog实现源代码中搜索nth1,网址为:
棘手的是,您必须生成或返回nth1项,这取决于您传入的未绑定变量。。所以在几行代码中可能不可能做到这一点。@EMS的答案相当不错,但正确实现该谓词可能很棘手。我们必须考虑在NTH1/4关系上有意义的每个实例化模式,因为问题需要完全相同的构建行为。因此,nth1还可以搜索元素并在位置处插入 SWI Prolog用于在不同实现之间进行效率切换,但应该可以在需要时对关系建模,以测试实例化 我称之为mth1而不是nth1
mth1(1, [X|R], X, R).
mth1(_, L, _, _) :-
L == [], % (==)/2 fails when L is a var
!, fail.
mth1(P, [H|T], X, [H|R]) :-
( var(P) % are we searching the position?
-> mth1(Q, T, X, R),
P is Q + 1
; Q is P - 1,
mth1(Q, T, X, R)
).
插入时需要测试L=[]
当然,调试是必需的,下面是一些简单的测试:
?- mth1(2,[a,b,c,d,e],X,Y).
X = b,
Y = [a, c, d, e] ;
false.
?- mth1(X,[a,b,c,d,e],b,Y).
X = 2,
Y = [a, c, d, e] ;
false.
?- mth1(2,X,b,[a,c,d,e]).
X = [a, b, c, d, e] ;
false.
您应该检查是否涵盖了SWI Prolog允许的所有实例化模式
如何执行这个简单的实现?这里有一个基本的测试
test_performance(N) :-
numlist(1, N, L),
time(test_performance(L, N, nth1)),
time(test_performance(L, N, mth1)).
test_performance(L, N, P) :-
writeln(P),
writeln('access last'),
time((call(P, N, L, X, _), assertion(X == N))),
writeln('find position of last'),
time((call(P, Z, L, N, _), assertion(Z == N))),
writeln('add tail'),
time(call(P, N, _, tail, L)).
令我惊讶的是,窥视元素和添加尾部的速度(稍微)更快,而查找位置的速度则慢得多(因为缺少尾部递归?)
事实上,对于较长的列表,职位搜索显示出其效率低下,典型的StackOverflow:
?- test_performance(2000000).
nth1
access last
% 2,000,011 inferences, 1,218 CPU in 1,221 seconds (100% CPU, 1641399 Lips)
find position of last
% 2,000,003 inferences, 1,327 CPU in 1,330 seconds (100% CPU, 1507572 Lips)
add tail
% 2,000,009 inferences, 0,958 CPU in 0,960 seconds (100% CPU, 2088038 Lips)
% 6,000,243 inferences, 3,504 CPU in 3,511 seconds (100% CPU, 1712549 Lips)
mth1
access last
% 2,000,002 inferences, 1,116 CPU in 1,118 seconds (100% CPU, 1792625 Lips)
find position of last
% 1,973,658 inferences, 2,479 CPU in 2,485 seconds (100% CPU, 796219 Lips)
% 3,973,811 inferences, 3,595 CPU in 3,603 seconds (100% CPU, 1105378 Lips)
ERROR: Out of local stack
首先,将问题分解为更小的组成部分。从列表中选择第n项很容易。收集的差别就不那么大了 因此,将其分为两部分:
- 首先,将列表分成前缀、所需项和后缀
- 接下来,通过
连接前缀和后缀以形成余数列表append/3
my\u nth1\4
谓词应该如下所示:
nth1( N , List , Nth, Rest ) :-
burst( N , List , Pfx , Nth , Sfx ) ,
append( Pfx , Sfx , Rest )
.
% ------------------------------------------------------------------------------
% burst a list into 3 parts - a prefix, an item and a suffix
% based on the specified offset N (where 0 indicates the first item of the list)
%
% The prefix is built up using a "difference list" as we recurse down looking
% for the Nth item.
% ------------------------------------------------------------------------------
burst( 0 , [L|Ls] , [] , L , Ls ).
burst( N , [L|Ls] , [L|Pfx] , Nth , Sfx ) :-
N > 0 ,
N1 is N - 1 ,
burst( N1 , Ls , Pfx , Nth , Sfx )
.
根据问题的性质和原始海报的处理方式,标记为家庭作业(Carleton U)
nth1( N , List , Nth, Rest ) :-
burst( N , List , Pfx , Nth , Sfx ) ,
append( Pfx , Sfx , Rest )
.
% ------------------------------------------------------------------------------
% burst a list into 3 parts - a prefix, an item and a suffix
% based on the specified offset N (where 0 indicates the first item of the list)
%
% The prefix is built up using a "difference list" as we recurse down looking
% for the Nth item.
% ------------------------------------------------------------------------------
burst( 0 , [L|Ls] , [] , L , Ls ).
burst( N , [L|Ls] , [L|Pfx] , Nth , Sfx ) :-
N > 0 ,
N1 is N - 1 ,
burst( N1 , Ls , Pfx , Nth , Sfx )
.