为什么循环引用和递归使我的程序失败?

时间:2011-11-13 00:21:39

标签: recursion prolog infinite-loop circular-reference

我写了这个简单的Prolog程序。

man(socrates).
mortal(X) :- man(X).
immortal(X) :- immortal(X).

我问过常见的问题,比如苏格拉底是男人还是苏格拉底是凡人。

?- man(socrates).
true.                    //we know for a fact that Socrates is a man
?- mortal(socrates).
true.                    //and it can logically be inferred that Socrates is mortal
?- immortal(socrates).
                         //but we can't seem to figure out if he's immortal

由于immortal的递归定义而崩溃了。循环引用也会使Out of stack space.

崩溃或出错

在我看来,至少在这种情况下,Prolog先生得出的结论是,根据该计划的规则,无法推断苏格拉底是不朽的,这是相当微不足道的。怎么样?我想它可以检查堆栈并查看它是否遍历已经遍历的规则。

有没有原因尚未实施?这样做会有一些问题,我忽略了,还是Prolog的实现已经进行了这样的分析?

4 个答案:

答案 0 :(得分:6)

  

在我看来,至少在这种情况下,Prolog先生得出的结论是,根据该计划的规则,无法推断苏格拉底是不朽的,这是相当微不足道的。

Prolog使用不完整的推理算法来提高效率。它本来是一种编程语言,除了程序性的程序之外,程序还具有逻辑意义,而不是一个完整的定理证明者。您必须小心编写子句的顺序,防止循环定义等。

至于谓词immortal的逻辑含义,它是

immortal(X) -> immortal(X)

这是一个重言式,可以在不改变其逻辑含义的情况下从您的程序/理论中删除。这意味着你应该删除它,如果这有助于改善程序意义(摆脱无限循环)。

答案 1 :(得分:3)

将表格与XSB一起使用:

:- table foo/1.

foo(X) :- foo(X).

bar(X) :- bar(X).

然后:

| ?- [tabled].
[tabled loaded]

yes
| ?- foo(1).

no
| ?- bar(1).    % does not finish

答案 2 :(得分:2)

您的定义 - 以及您如何解释它们:

man(socrates).

苏格拉底是一个男人。

mortal(X) :- man(X).

每个人都是凡人。

immortal(X) :- immortal(X).

每一个不朽都是不朽的。


您的定义 - 以及Prolog如何解释它们:

man(socrates).

如果你问苏格拉底的男子气概,我知道这是真的。

mortal(X) :- man(X).

如果你问我某人的死亡率,我会检查他的男子气概(如果这是真的,那么死亡率也是如此)。

immortal(X) :- immortal(X).

如果你问我某人的不朽,我会检查他的不朽。 (你是否仍然想知道这会导致无限循环?)


如果你想说一个人是不朽的,如果他不能被证明是凡人,那么你可以使用:

immortal(X) :- not( mortal(X) ).

答案 3 :(得分:0)

这个小程序怎么样:

 loopy(Y) :- read(X), Z is X+Y, print(Z), nl, loopy(Y).

你的Prolog先生会推断,已经调用了loopy(Y)并且会失败。