3

我写这个程序给我这个结果:“X=john”“Y=jane”

likes(john,mary).
likes(mary,jane).
likes(l,k).

likes(X,Y) :- likes(X,Z), likes(Z,Y).

但是如果运行这个程序这样结果:我认为程序进入循环!我想在真实答案后停下来!

1 ?- likes(X,Y).
X = john,
Y = mary ;
X = mary,
Y = jane ;
X = l,
Y = k ;
X = john,
Y = jane ;
ERROR: Out of local stack

我有错误!如何解决这个问题?

通过调试:

[debug] 3 ?- likes(john,Y).
 T Call: (6) likes(john, _G2162)
 T Exit: (6) likes(john, mary)
Y = mary ;
 T Redo: (6) likes(john, _G2162)
 T Call: (7) likes(john, _G2267)
 T Exit: (7) likes(john, mary)
 T Call: (7) likes(mary, _G2162)
 T Exit: (7) likes(mary, jane)
 T Exit: (6) likes(john, jane)
Y = jane ;
 T Redo: (7) likes(mary, _G2162)
 T Call: (8) likes(mary, _G2267)
 T Exit: (8) likes(mary, jane)
 T Call: (8) likes(jane, _G2162)
 T Call: (9) likes(jane, _G2267)
 T Call: (10) likes(jane, _G2267)
 T Call: (11) likes(jane, _G2267)
 T Call: (12) likes(jane, _G2267)
 T Call: (13) likes(jane, _G2267)
 T Call: (14) likes(jane, _G2267)
 T Call: (15) likes(jane, _G2267)

等等..为什么喜欢(简,_G2267)??????

4

3 回答 3

3

X您的查询(Y都是变量)对于您定义的方式来说太“广泛”了likes/2

尝试

?- likes(john, Y).

Prolog 引擎是做什么的?好吧,它在其事实数据库中进行搜索。


首先它发现(第一条规则)

likes(john, mary).

所以约翰喜欢玛丽


然后它发现

likes(john,Y) :-
    likes(john,Z),
    likes(Z,Y).

所以它问自己:Z 是真的likes(john,Z)吗?好吧,数据库这么说likes(john, mary),所以Z = mary。让我们把它放在规则中:

likes(john,Y) :-
    likes(john,mary),
    likes(mary,Y).

所以它问自己:Y 是真的likes(mary,Y)吗?好吧,数据库这么说likes(mary, jane),所以Y = jane。让我们把它放在规则中:

likes(john,jane) :-
    likes(john,mary),
    likes(mary,jane).

所以约翰喜欢简


现在我们有一个问题。仔细查看第二个查询:

likes(john,Y) :-
    likes(john,Z),
    .....

哦哦。

如果约翰喜欢某人,约翰就喜欢某人(并且,.....)

好吧,在第一次尝试时我们很幸运:Prolog 引擎找到了Y = jane, Z = mary,因为我们有以下规则

likes(john,mary).
likes(mary,jane).

它停止了。但随后它又问自己:

likes(john,Y) ?

我们已经使用了前两个规则,所以让我们尝试第三个:

likes(X,Y) :-
    likes(X,Z),
    likes(Z,Y).

麻烦!

likes(john,Someone) :-
    likes(john,Someone2), ..... 

likes(john,Someone2) :-
    likes(john,Someone3), .....

likes(john,Someone3) :-
    likes(john,Someone4), .....

等等..

于 2013-04-10T20:35:55.287 回答
3

如果你需要 "X=john" "Y=jane" 那么你必须重命名:

likes(X,Y) :- likes(X,Z), likes(Z,Y).

对于其他名称,例如:

likestransitive(X,Y) :- likes(X,Z), likes(Z,Y).

因此,您可以获得所需的解决方案:

1 ?- transitivelikes(X,Y).    
X = john,    
Y = jane;    
false.
于 2013-04-10T20:43:31.703 回答
2

你的代码:

likes(john,mary).          % {1}
likes(mary,jane).          % {2}
likes(l,k).                % {3}

likes(X,Y) :-              % {4}
    likes(X,Z),            % {5} 
    likes(Z,Y).            % {6}

查询likes(john,Y)进行如下:

likes(john,Y)? 
%% {1}  Y = mary.        ; redo
%% {4}  likes(john,Y) :-
   %% {5}  likes(john,Z)?
      %% {1}  Z=mary.
   %% {6}  likes(mary,Y)?
      %% {2}  Y=jane.        ; redo
      %% {4}  likes(mary,Y) :-
         %% {5}  likes(mary,Z2)?
            %% {2}  Z2=jane,
         %% {6}  likes(jane,Y)?
            %% {4}  likes(jane,Y):-
               %% {5}  likes(jane,Z3)?
                  %% {4}  likes(jane,Z3):-
                     %% {5}  likes(jane,Z4)?
                     ............

这就是你在调试器中看到的。

为了防止这种行为,重命名传递闭包谓词,如下所示:

likes(john,mary).          % {1b}
likes(mary,jane).          % {2b}
likes(l,k).                % {3b}

pals(X,Y) :-               % {4b}
    likes(X,Z),            % {5b} 
    pals(Z,Y).             % {6b}
于 2013-04-11T09:58:47.267 回答