Prolog帮助 - 无法理解规则

时间:2012-01-13 17:37:32

标签: database prolog rules

我有一个充满事实的数据库,例如:

overground( watfordjunction   , watfordhighstreet , 2 ).
overground( watfordhighstreet , bushey            , 3 ).
overground( bushey            , carpenderspark    , 3 ).
overground( carpenderspark    , hatchend          , 2 ).
例如:watford交界处到watfordhighstreet需要2分钟。

然后我设计了一条规则,以便我可以测试是否可以完成从任何车站到另一个车站的旅程,包括任何反向旅程。

isjourney( Station1 , Station2 ) :-
  overground( Station1 , _        , _ ) ,
  overground( _        , Station2 , _ ) ; 
  overground( Station2 , _        , _ ) ,
  overground( _        , Station1 , _ )
  .
isjourney( Station1 , Station2 ) :-
  overground( Station1 , Station3 , _ ) ,
  isjourney(  Station3 , Station2 )
  .
isjourney( Station1 , Station2 ) :-
  overground( Station4 , Station2 , _ ) ,
  isjourney(  Station1 , Station4 )
  .

(原谅下划线,我无法粘贴它们)

最后我提出了一个可行的方法,但是我只是在试错后才想出来,所以我无法解释它是如何工作的,甚至是它的作用......任何有经验的人都可以向我解释它的作用?

3 个答案:

答案 0 :(得分:1)

你的第一个条款是错误的。 它应该是

isjourney(Station1, Station2):- 
  overground(Station1, Station2, _).

其他条款似乎没问题,但你可以把它们放在一个条款中:

isjourney(Station1,Station2):-
    (overground(Station1,Station3,_), isjourney(Station3,Station2)) ; 
    (overground(Station3,Station2,_), isjourney(Station1,Station3)) .

基本上你所说的是,如果地上Station1和Station2成功,或者有一个中间站(Station3),你可以从Station1到Station3,然后从Station3到Station2(或者反向旅程)。

答案 1 :(得分:1)

我假设你正在服用@DavidGregg正在服用的同一个班级。我对https://stackoverflow.com/questions/8789021/basic-prolog-but-struggling/8794162#8794162的回答可能对您有帮助。

FWIW,prolog变量_是匿名/“不关心”变量。名为____的变量是匿名/“不关心”。匿名变量与任何东西统一,统一不会延续,所以给出的事实如下:

number(1).
letter(a).

一个谓词,如

foo :- number(_) , letter(_).

会成功,而

foo :- number(____) , letter(____) .

不会。

在你的第一个条款中

isjourney( Station1 , Station2 ) :-
  overground( Station1 , _        , _ ) ,
  overground( _        , Station2 , _ ) ; 
  overground( Station2 , _        , _ ) ,
  overground( _        , Station1 , _ )
  .

你确定它与你认为它绑定的方式有关吗?

就像过程语言的语法一样,prolog的AND和OR运算符的优先级不同。如果您要使用OR运算符;,则应该对事物进行括号化以使预期的绑定清晰。不过,恕我直言,更好的是完全避免它:

isjourney( Station1 , Station2 ) :-
  overground( Station1 , _        , _ ) ,
  overground( _        , Station2 , _ )
  .
isjourney( Station1 , Station2 ) :- 
  overground( Station2 , _        , _ ) ,
  overground( _        , Station1 , _ )
  .

您的基本想法是正确的:A站和B站之间的路线存在如果

  • 站A存在,
  • 站B存在,
  • 站A和某个中间站X之间存在直接路由,
  • 在中间站X和站B之间存在路线

我相信你遗漏了一个案例:A站和B站直接相邻。

但是,我要注意,显式检查电台的存在并不是必要的:如果电台不存在,则谓词不能成功。

我倾向于写谓词

isjourney(A,B) :-
  station_exists(A) ,   % verify that station A exists
  station_exists(B) ,   % verify that station B exists
  (
    route_exists(A,B)   % verify that a route exists between A and B
    ;                   % in either direction
    route_exists(B,A)
  )
  .

route_exists(A,B) :- % 1st, check for directly adjacent stations
  overground(A,B,_) ,
  .
route_exists(A,B) :- % 2nd, check for indirect routes
  overground(A,T,_) ,
  route_exists(T,B)
  .

% =========================================================
% check for the existence of a station
% we want the cut to alternatives. A station exists or it doesn't
% we don't want backtracking to succeed by finding every instance
% of the station
% in the route map.
% =========================================================
station_exists(X) :- overground(X,_,_) , ! .
station_exists(X) :- overground(_,X,_) , ! .

回溯当然应该列举两个方向上的所有可能路线。

正如我在上面的回答中所指出的,如果图中存在一个循环,该解决方案仍然容易受到无底递归的影响(例如,如果站A链接到站B,站B链接到站C和A) )。您可以选择检测此类周期。

答案 2 :(得分:0)

我猜你试图回答与the person in this question相同的事情。

首先,你应该使用你的问题2回答:

基本情况,如果有直接旅程:

is_journey(Station1, Station2) :-
    q2(Station1, Station2).

不是基本情况,你必须使用中间件:

is_journey(Station1, Station2) :-
    q2(Station1, StationTemp),
    is_journey(StationTemp, Station2).

现在,这不会处理周期:你可能会陷入无限循环,所以要处理它们,你应该选择:

首先,我们调用一个谓词,它将调用相同的谓词但有3个参数(最后一个跟踪所使用的站点):

is_journey(Station1, Station2) :-
    is_journey(Station1, Station2, [Station1]).

然后我们使用相同的基本情况:

is_journey(Station1, Station2, _) :-
    q2(Station1, Station2).

然后我们使用几乎相同的递归情况,但我们检查Visited中的成员身份,并在继续递归时更新Visited

is_journey(Station1, Station2, Visited) :-
    q2(Station1, StationTemp),
    \+ member(StationTemp, Visited),
    is_journey(StationTemp, Station2, [StationTemp|Visited]).

BTW我不认为你的OP谓词是正确的,因为它只检查两个站是否真的是站,而不是两者都是直接连接。