Prolog不计算列表的变量

Prolog不计算列表的变量,prolog,Prolog,在我的编程课程中,我有一个任务,在那里我可以找到中途停留的火车。这就是为什么我给出两个变量,X代表到达时间,Y代表中途停留列表。但我只得到了X。我怎样才能让你也回来 station(a). station(b). station(c). station(d). train(a, b, 8.03, 9.15). train(b, c, 9.18, 10.26). train(c, d, 10.28, 11.02). % circular connection train(c, d, 11.20

在我的编程课程中,我有一个任务,在那里我可以找到中途停留的火车。这就是为什么我给出两个变量,X代表到达时间,Y代表中途停留列表。但我只得到了X。我怎样才能让你也回来

station(a).
station(b).
station(c).
station(d).

train(a, b, 8.03, 9.15).
train(b, c, 9.18, 10.26).
train(c, d, 10.28, 11.02).

% circular connection
train(c, d, 11.20, 12.44).
train(d, c, 13.02, 14.34).

% When changing trains, departure time > arrival time applies.
% The train should not go in circles, therefore the Y should not contain
% any station more than once.

connection(Start, Destination, TDeparture, TArrival, _) :- 
    train(Start, Destination, Departure, TArrival),  Departure > TDeparture.


connection(Start, Destination, TDeparture, TArrival, Stops) :-
    station(Start),
    station(Destination),
    station(Stop),    
    train(Start, Stop, Departure, Arrival),
    Departure > TDeparture,
    connection(Stop, Destination, Arrival, TArrival, [Stop | Stops]).


% Query connection from a to d, starting after 8.00
% X = Arrival time
% Y = List of stops

% connection(a, d, 8.00, X, Y).

% Should get me:
% X = 11.02
% Y = [c, b];
% X = 12.44
% Y = [c, b]

% but i got only this:
% X = 11.02 ;
% X = 12.44

您的基本情况有一个自由变量,因此它不会更改传递给它的任何内容。由于递归案例从不将值绑定到
Stops
,因此它始终是一个自由变量。因此Y只是Y,不显示

您实际问题的答案在最后,但在此之前,我将展示更简单的方法

无需尾部呼叫优化的简单解决方案

这从基本情况下的一个空列表开始,并在返回时建立它,而不是将一个不断增长的列表推到基本情况下。这将导致顺序颠倒。你可以做一个附加操作来获得正确的顺序


% was connection(Start, Destination, TDeparture, TArrival, _)
connection(Start, Destination, TDeparture, TArrival, []) :-  
    train(Start, Destination, Departure, TArrival),  Departure > TDeparture.

% was connection(Start, Destination, TDeparture, TArrival, Stops)
connection(Start, Destination, TDeparture, TArrival, [Stop | Stops]) :-
    station(Start),
    station(Destination),
    station(Stop),    
    train(Start, Stop, Departure, Arrival),
    Departure > TDeparture,
% was connection(Stop, Destination, Arrival, TArrival, [Stop|Stops])
    connection(Stop, Destination, Arrival, TArrival, Stops).

使用额外累加器优化尾部呼叫

实现尾部调用优化的最简单方法是使用单独的累加器参数。(或者我希望它能实现)。这里的顺序又错了,但是您仍然可以使用append/3来修复它

% Query with connection(a, d, 8.00, X, [], Y).
% Or define wrapper 
%    connection(a, d, 8.00, X, Y):- connection(a, d, 8.00, X, [], Y).
connection(Start, Destination, TDeparture, TArrival, StopsSoFar, StopsSoFar) :- 
    train(Start, Destination, Departure, TArrival),  Departure > TDeparture.


connection(Start, Destination, TDeparture, TArrival, StopsSoFar, FinalStops) :-
    station(Start),
    station(Destination),
    station(Stop),    
    train(Start, Stop, Departure, Arrival),
    Departure > TDeparture,
    connection(Stop, Destination, Arrival, TArrival, [Stop | StopsSoFar], FinalStops).
% If you want it in the right order, 
    %   append(Stop, StopsSoFar, NextStopsSoFar),
    %   connection(Stop, Destination, Arrival, TArrival, NextStopsSoFar, FinalStops).
实际答案

如果允许我猜你想做什么,你想传递一条自由的尾巴,这样它可以一直增长到基本情况([a,b,c,…| T])

这方面的困难在于找到一种有效地将头部与T分离并修改T(T=[d|U])的方法。这是我用safe_split/3做的尝试。我没有花太多心思

connection(Start, Destination, TDeparture, TArrival, Stops) :-
    safe_split(_,T, Stops), T= [],
    train(Start, Destination, Departure, TArrival),  Departure > TDeparture.


connection(Start, Destination, TDeparture, TArrival, Stops) :-
    station(Start),
    station(Destination),
    station(Stop),    
    train(Start, Stop, Departure, Arrival),
    Departure > TDeparture,
    safe_split(_,T, Stops), 
    T = [Stop|_],
    connection(Stop, Destination, Arrival, TArrival, Stops).

safe_split(H,T,Stops):-
    append(H,T,Stops), var(T), % lots of backtracking because generate & test.
    !. % Prevent free variables appended to the head.
附录:

?-start(a,d,8.00,X,Y)
X = 11.02,
Y = [c, b]
X = 12.44,
Y = [c, b]

?-start(a,c,9.00,X,Y)
false

?-start(a,c,8.00,X,Y)
X = 10.26,
Y = [b]
false

?-start(b,c,8.00,X,Y)
X = 10.26,
Y = []
false

?- start(d,c,8.00,X,Y).
X = 14.34,
Y = []
来演示在没有切割的情况下会发生什么

?- L=[a,b,c|_], append(X,Y,L), var(Y).
L = [a, b, c|Y],
X = [a, b, c] ;

L = [a, b, c, _5368|Y],
X = [a, b, c, _5368] ;

L = [a, b, c, _5368, _5380|Y],
X = [a, b, c, _5368, _5380]

% ... and so on.

感谢有趣的操作,如果我向您扔了太多东西,我很抱歉:)

1-开始谓词获取开始节点、结束节点、时间,并给出X(到达时间)和Y(两者之间的连接节点)

2-连接谓词检查连接节点,如果Time2大于Time1,则将节点推到列表中。该列表用于Y。该列表提供了整个路径
[a,b,c,d]
,因此我们使用
removeHead
removeTail
谓词进一步删除列表中的第一个和最后一个元素。最后,我们反转列表得到Y(这是可选的)

3-
arrivalTime
谓词为我们提供了X的所有可能值。但我们使用
@
?-start(a,d,8.00,X,Y)
X = 11.02,
Y = [c, b]
X = 12.44,
Y = [c, b]

?-start(a,c,9.00,X,Y)
false

?-start(a,c,8.00,X,Y)
X = 10.26,
Y = [b]
false

?-start(b,c,8.00,X,Y)
X = 10.26,
Y = []
false

?- start(d,c,8.00,X,Y).
X = 14.34,
Y = []