Recursion 为什么循环引用和递归使我的程序失败?
我写了这个简单的Prolog程序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
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的未定义谓词不会失败,但会导致错误。