为什么这些类似的计划有不同的结果?

时间:2017-09-25 10:19:08

标签: prolog

我正在做一个要求实现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.但结果完全不同。 有谁知道是什么原因引起的?

1 个答案:

答案 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).

现在两种解决方式非常相似,只需更改第二个子句的顺序。