【问题标题】:Prolog Help - Cant Understand a RuleProlog 帮助 - 无法理解规则
【发布时间】:2012-01-13 17:37:31
【问题描述】:

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

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

(请原谅下划线,我在粘贴时遇到了问题)

最后我想出了工作正常的方法,但是我只是在反复试验后才设法想出它,所以我无法解释它是如何工作的,甚至无法解释它在做什么......任何人都可以体验过 prolog解释一下它的作用?

【问题讨论】:

  • 对不起,我在顶部提到的所有事实都是为了被称为​​地上而不是车站,当您拥有相同文件 xD 的 5 个版本时会发生这种情况。无论如何,我进行了编辑,希望现在事情变得有意义,在事实中定义了地面。

标签: database prolog rules


【解决方案1】:

我假设你正在上 @DavidGregg 正在上的同一门课。我对https://stackoverflow.com/questions/8789021/basic-prolog-but-struggling/8794162#8794162 的回答可能会对您有所帮助。

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

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】:

    您的第一个子句是错误的。 应该是

    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(或反向旅程)。

    【讨论】:

      【解决方案3】:

      我猜你想回答和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]).
      

      顺便说一句,我不认为你的 OP 谓词是正确的,因为它只检查两个站是否真的是站,而不是如果两者都直接连接。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-29
        • 1970-01-01
        相关资源
        最近更新 更多