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

我编写了这个简单的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.错误Out of stack space.

在我看来,至少在这种情况下,对于普罗洛先生来说,从计划规则中得出的结论是相当微不足道的,不能断定苏格拉底是不朽的。 怎么样? 我想它可以检查堆栈并查看它是否正在遍历已经遍历的规则。

有没有理由为什么这还没有实施? 这样做是否会出现一些问题,以致于我忽略了这些问题,还是有Prolog的实现已经执行了此类分析?


在我看来,至少在这种情况下,对于普罗洛先生来说,从计划规则中得出的结论是相当微不足道的,不能断定苏格拉底是不朽的。

Prolog使用不完整的推理算法来提高效率。 它意味着一种编程语言,程序除了程序之外还具有逻辑意义,而不是全面的定理证明。 你必须小心编写条款的顺序,防止循环定义等。

至于你的谓语immortal的逻辑意义,它是

immortal(X) -> immortal(X)

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


与XSB一起使用表格:

:- table foo/1.

foo(X) :- foo(X).

bar(X) :- bar(X).

接着:

| ?- [tabled].
[tabled loaded]

yes
| ?- foo(1).

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

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

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) ).
链接地址: http://www.djcxy.com/p/66929.html

上一篇: Why do circular references and recursion make my program fail?

下一篇: Node streams cause large memory footprint or leak