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

Recursion 为什么循环引用和递归使我的程序失败?,recursion,prolog,infinite-loop,circular-reference,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 ca

我写了这个简单的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(X) :- immortal(X).
由于
不朽
的递归定义,它崩溃了。循环引用也会导致堆栈空间不足而崩溃或出错。

在我看来,至少在这种情况下,普洛格先生得出结论说,根据程序中的规则,不能推断苏格拉底是不朽的,这是相当微不足道的。怎么用?我想它可以检查堆栈,看看它是否正在遍历已经遍历的规则


这是否有尚未实施的原因?这样做是否会有一些我忽略的问题,或者是否有Prolog的实现已经执行了此类分析?

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

man(socrates).
苏格拉底是个男人

mortal(X) :- man(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(X) :- immortal(X).
每个不朽的人都是不朽的



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

man(socrates).
如果你问苏格拉底的男子气概,我知道这是真的

mortal(X) :- man(X).
如果你问我某人的死亡率,我会检查他的男子气概(如果这是真的,那么死亡率也是)

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


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

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

这个小节目怎么样:

 loopy(Y) :- read(X), Z is X+Y, print(Z), nl, loopy(Y).
你的Prolog先生会推断,loopy(Y)已经被调用,将失败

在我看来,至少在这种情况下,普洛格先生得出结论说,根据程序中的规则,不能推断苏格拉底是不朽的,这是相当微不足道的

Prolog使用不完全推理算法来提高效率。它是一种程序设计语言,程序除了具有过程意义外,还具有逻辑意义,而不是完整的定理证明程序。你必须注意写子句的顺序,防止循环定义,等等

至于谓词
不朽
的逻辑意义,它是

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

使用tabling with:

然后:

| ?- [tabled].
[tabled loaded]

yes
| ?- foo(1).

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

你是说不朽的定义是他是不朽的吗?你是在寻找“tabling”,尽管只有少数prolog实现支持它(例如XSB或YAP)。我理解为什么它可能是一个无限循环,但我假设a逻辑语言能够得出结论,
不朽
总是错误的。例如,假设堆栈溢出上有一个“递归”标记,而获取递归标记的唯一方法是获取递归标记,这是不可能的。如果希望不朽始终为false,则可以显式声明
不朽(X):-false。
或使用
不朽(X):-(我可能在这一点上错了,因为我多年没有使用Prolog)。对于这个简单的情况,它们是等价的,但是您可以有其他更复杂的情况,其中递归非常有用(可以使用
不朽(X):-
是错误的,它会说每个X都是不朽的。@PeterOlson,更正:如果您希望不朽始终为false,您可以显式声明
不朽(X):-false。
,这意味着每个X都不是不朽的。(而不是使用
不朽(X):-!。
正如Joe Lehmann指出的,这意味着相反,每个人都是不朽的。@Peter Olson:这是非常不同的。调用基于ISO Prolog的未定义谓词不会失败,但会导致错误。