为什么循环引用和递归使我的程序失败?
我编写了这个简单的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?