循環参照と再帰によって私のプログラムが失敗するのはなぜですか?

私はこのシンプルな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

It crashed because of the recursive definition of immortal. Circular references also make it crash or error with Out of stack space.

少なくともこの場合は、プロロッグ氏がプログラムのルールから、ソクラテスが不滅であると推論することはできないと結論づけることはかなり些細なことだと私は思う。どうやって?私はそれがスタックを調べて、すでに横断されているルールを横断しているかどうかを見ることができると思います。

これがまだ実装されていない理由はありますか?私が見落としているようなやり方で問題があるのでしょうか、すでにこのような分析を行っているPrologの実装がありますか?

3
あなたは不滅の定義は彼が不滅であるということですか?
追加された 著者 Lasse Vågsæther Karl,
@ LasseV.Karlsenはい。
追加された 著者 Peter Olson,
あなたは "テーブルリング"を探していますが、少数のプロローグ実装だけがそれをサポートしています(例えばXSBやYAP)。
追加された 著者 salva,

4 答え

少なくともこの場合、Prolog氏はプログラムのルールから、ソクラテスが不滅であると推測することはできないと結論づけることはかなり些細なことだと思う。

Prologは効率のために不完全推論アルゴリズムを使用します。これは、プログラムが論理的な意味を持っているプログラミング言語であることを意味しています。あなたは、句を書く順番、巡回詞の定義を妨げる順序などに注意する必要があります。

あなたの述語 immortal の論理的意味については、

immortal(X) -> immortal(X)

これは同音異義語であり、論理的な意味を変えずにプログラム/理論から削除することができます。これは、手順上の意味を改善するのに役立つ場合は削除する必要があることを意味します(無限ループを取り除きます)。

6
追加された

XSB での表の使用:

:- table foo/1.

foo(X) :- foo(X).

bar(X) :- bar(X).

その後:

| ?- [tabled].
[tabled loaded]

yes
| ?- foo(1).

no
| ?- bar(1).    % does not finish
4
追加された

あなたの定義とその解釈方法:

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
追加された
私はなぜそれが無限ループになるのか理解していますが、論理言語が immortal が常に偽であると結論付けることができると仮定しました。たとえば、Stack Overflowに「再帰」バッジがあり、再帰バッジを取得する唯一の方法は、再帰バッジを取得することです。取得することは不可能です。
追加された 著者 Peter Olson,
@ypercube immortal の定義を完全に省くほうが簡単でしょう。それは本質的に同じことを意味します。
追加された 著者 Peter Olson,
immortalを常にfalseにしたい場合は、明示的に immortal(X):-False。または immortal(X): - !を宣言することができます。間違って、何年もPrologを使っていない)。この単純なケースでは、それらは同等ですが、再帰が非常に便利な(そしてで停止することができる)他のより複雑なケースを持つこともできます
追加された 著者 ypercubeᵀᴹ,
@ JoeLehmann:あなたはもちろんコース外です。私は私のコメントを編集します。
追加された 著者 ypercubeᵀᴹ,
@PeterOlson、修正:永続を常に偽にしたい場合は、明示的に immortal(X):-False。を宣言することができます。 Joe Lehmannが指摘しているように、すべてが不滅であるとは逆の意味です( immortal(X): - ! ではない)。
追加された 著者 ypercubeᵀᴹ,
@Peter Olson:それは非常に異なっています。 ISO-Prologで宣言された未定義の呼び出しは失敗しませんが、エラーをトラフします。
追加された 著者 salva,
(oops、s/troughs/throws /)
追加された 著者 salva,
immortal(X): - !。が間違っていれば、すべてのXが不滅であると言います。
追加された 著者 Joe Lehmann,

この小さなプログラムはどうですか?

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

あなたのMr.Prologは、虚偽の(Y)が既に呼び出されて失敗すると推測します。

0
追加された