我正在做一个要求实现from_to/3
的练习,在这里你给两个数字作为前两个参数,Prolog给你一个列表,列出它们之间的所有结果。例如:from_to(1,5,R)
会给R=[1,2,3,4,5]
。
我写了以下程序:
fromto(N, O, []):-
N >= O.
fromto(N, O, [N|TailResult]):-
O > N,
O1 is O-1,
fromto(N, O1, TailResult).
使用查询fromto(3,8,R)
,它返回五个3的列表。不好。
处理它的正确方法是:
from_to(N, O, []) :-
N > O.
from_to(N, O, [N|TailResult]) :-
N =< O,
N1 is N + 1,
from_to(N1, O, TailResult).
这会按预期提供list 3,4,5,6,7,8
。
我的问题是这是如何运作的。这些程序的不同之处仅在于我用O从上到下工作,正确的工作向上加上N.但结果完全不同。 有谁知道是什么原因引起的?
答案 0 :(得分:2)
问题在于,在你的第一次尝试中,第一个参数-N不会仅仅改变O改变,并且你递归地将N放在列表中,所以你要看的就是N的列表。< / p>
如果你想保留这种方法,你必须每次将O放在列表中:
fromto(N, O, []):-
N > O.
fromto(N, O, L):-
O >= N,
O1 is O-1,
fromto(N, O1, L2),
append(L2,[O],L).
此实现的问题是您需要使用append/3
才能按顺序放置,否则您将获得反向列表。这不是那么有效,因为每次你需要在列表中添加一个元素时,你需要遍历所有列表并将它放在那会产生额外开销的地方。
实施例
?- fromto(3,8,L).
L = [3, 4, 5, 6, 7, 8] ;
false.
你也可以按照@false的建议使用DCG:
from_to(N,N) -->[N].
from_to(N,O) --> [N],{N<O, N1 is N+1},from_to(N1,O).
final_solution(N,O,L):- phrase(from_to(N,O),L).
另一种方式(减少O而不是N):
from_to(N,N) -->[N].
from_to(N,O) --> {N<O, O1 is O-1},from_to(N,O1),[O].
final_solution(N,O,L):- phrase(from_to(N,O),L).
现在两种解决方式非常相似,只需更改第二个子句的顺序。