2

推移的な関係を表現したい。A が B を参照し、B が C を参照する場合、A は C を参照します。

proj(A).
proj(B).
proj(C).
ref(A,B).
ref(B,C).

を使用してクエリを実行すると、次のようになりますproj(A)

[46] ?-proj(A)。
A = _639

"_639" とはどういう意味ですか? はいまたはいいえを期待していたので、その奇妙さを得ました。次のルールを追加する必要があります。

ref(A,C).はい。理想的には、可能であれば、この関係 (A => B => C) がどのように生じたかを示したいと思います。

4

1 に答える 1

8

_639、インスタンス化されていない匿名変数です。あなたの「事実」には、アトムではなく変数があります。例えば:

proj(A).   % This has a variable A and means "any A is a project"

したがって、クエリを実行すると:

:- proj(X).
X = _blah    % anonymous variable: anything is a project!

アトムが必要です:

proj(a).
proj(b).

クエリの結果は次のとおりです。

:- proj(X).
X = a ;
X = b 

あなたが持っている場合:

ref(a,b).
ref(b,c).

次に、Prolog で推移的なプロパティを表現する最も簡単な方法は、ルール(またはPrologで述語と呼ばれるもの)を宣言することです。

ref(A,C) :- ref(A,B), ref(B,C).

これは、ref(A,C)が真であればref(A,B)真であり、ANDref(B,C)が真であることを示しています。. クエリの実行:

:- ref(a,c).
true ;
Out of stack

または:

:- ref(a,X).
X = b ;
X = c ;
Out of stack

したがって、論理的に聞こえますが、問題があります。自己参照が原因でループに入る可能性があります。これを回避する簡単な方法は、ルール名を事実とは異なるものにすることです。

refx(A, B) :- ref(A, B).
refx(A, C) :- ref(A, B), refx(B, C).

クエリを実行すると、次のようになります。

:- refx(a, b).
true ;
no

:- refx(a, c).
yes

:- refx(a, X).
X = b ;
X = c
yes

等。

ただし、ファクトに再帰的または可換的な関係が含まれている場合は、終了の問題が発生する可能性があります。例えば:

ref(a,b).
ref(b,a).
ref(b,c).

この場合、次のクエリがrefx(a, b)生成されます。

| ?- refx(a, b).
true ? ;
true ? ;
true ? ;
...

@lambda.xy.x が指摘しているように、これはどこに行ったかを追跡し、繰り返しの「訪問」を避けることで解決できます。

refx(X, Y) :-
    refx(X, Y, []).

refx(X, Y, A) :-
    ref(X, Y),
    \+ memberchk((X, Y), A).   % Make sure we haven't visited this case
refx(X, Y, A) :-
    ref(X, Z),
    \+ memberchk((X, Z), A),   % Make sure we haven't visited this case
    refx(Z, Y, [(X,Z)|A]).

ここで終了しrefx(a,b)、一度成功します。

| ?- refx(a,b).
true ? ;
no
| ?-

そしてrefx(X, Y)、すべてのソリューションを生成します(ただし、複数回成功するため、一部は繰り返されます):

| ?- refx(X, Y).

X = a
Y = b ? ;

X = b
Y = a ? ;

X = b
Y = c ? ;

X = a
Y = a ? ;

X = a
Y = c ? ;

X = b
Y = b ? ;

X = b
Y = c ? ;

(2 ms) no
于 2015-02-19T19:56:13.430 に答える