ユーザーが照会できないルールを定義するにはどうすればよいですか? プログラム自体が別のルールを介してこのルールを呼び出すようにしたいだけです。
元:
ルール 1():- ルール 2()。
rule2():- 1<5.
?-rule1()。
真実
?-rule2()。
(答えがどうなるかわかりません。このクエリを失敗させたいだけです!)
Logtalkオブジェクトを使用して、述語をカプセル化します。publicと宣言した述語のみを(オブジェクトの外部から)呼び出すことができます。明示的な修飾を使用すると、明示的にエクスポートされた述語のリストがバイパスされるため、Prologモジュールは述語の呼び出しを妨げません。
簡単な例:
:- object(rules).
:- public(rule1/1).
rule1(X) :-
rule2(X).
rule2(X) :-
X < 5.
:- end_object.
上記のオブジェクトをコンパイルしてロードした後:
?- rules::rule1(3).
true.
?- rules::rule2(3).
error(existence_error(predicate_declaration,rule2(3)),rules::rule2(3),user)
オブジェクトコードを編集し、rule2 / 1をプライベートとして明示的に宣言すると、代わりに次のエラーが発生します。
?- rules::rule2(3).
error(permission_error(access,private_predicate,rule2(3)),rules::rule2(3),user)
http://logtalk.org/でより多くの情報とたくさんの例
まず、いくつかの注意事項:
「ルール」ではなく「述語」を意味していると思います。述語は(and is another) のname/k
ようなものであり、複数の節を持つことができます。その中には事実と規則があります。たとえば、(a fact) と(a rule) は 1 つの述語の 2 つの節です。help/0
help/1
length([], 0).
length([H|T], L) :- ... .
length/2
引数のない述語に空の括弧を使用しないでください。少なくとも SWI-Prolog では、これはまったく機能しません。すべての場所でpredicate2
代わりに使用してください。predicate2()
未定義の述語を呼び出そうとすると、SWI-Prolog は言いERROR: toplevel: Undefined procedure: predicate2/0 (DWIM could not correct goal)
、Sicstus-Prolog は言います。{EXISTENCE ERROR: predicate2: procedure user:predicate2/0 does not exist}
では、答えに。2つのアイデアが頭に浮かびます。
(1) これはハックですが、述語が必要になるたびにアサートし、その後すぐに撤回することができます。
predicate1 :-
assert(predicate2), predicate2, retractall(predicate2).
の本体と引数が必要な場合はpredicate2
、 を実行してくださいassert(predicate2(argument1, argument2) :- (clause1, clause2, clause3))
。
(2) これを達成する別の方法は、ユーザーによって呼び出されたくない述語に追加の引数を導入し、ユーザーが提供できない可能性があるが、呼び出しから提供できる識別に使用することです。述語。これは、ランダムに見える大きな定数、または文でさえあるかもしれません。これにより、間違った ID が提供された場合にカスタム エラー メッセージを出力することもできます。
例:
predicate1 :-
predicate2("Identification: 2349860293587").
predicate2(Identification) :-
Identification = "Identification: 2349860293587",
1 < 5.
predicate2(Identification) :- Identification \= "Identification: 2349860293587",
write("Error: this procedure cannot be called by the user. Use predicate1/0 instead."),
fail.
predicate2("Identification: 2349860293587")
の最初の句に相当するものは使用しません。これpredicate2/0
は、節の先頭が Prolog メッセージのどこに表示されるかがわからず、あなたがそれを望まないためです。fail
Prologがエラー メッセージfalse
の後ではなく出力するように、2 番目の句の最後にa を使用します。true
そして最後に、ユーザーがソースコードを調べないようにする方法がわからないlisting(predicate2)
ので、本当に必要な場合は正しい識別コードを簡単に調べることができます。ただし、ユーザーが偶発的な危害を加えないようにするためだけであれば、保護としては十分です。
これは、Java にある機能を思い起こさせます。そこでは、現在のコール スタックを照会し、これを使用してメソッドを呼び出す権限を調整できます。Prolog に翻訳すると、古い DEC-10 Prolog には次の述語があります。
祖先(L)
現在の句の祖先ゴールのリストで L を統合します。リストは親ゴールで始まり、コンパイルされた句の呼び出しからの最新の祖先で終わります。リストは print を使用して出力され、各エントリの前に括弧で囲まれた呼び出し番号が続き、その後に深度番号が続きます (トレース メッセージで示されるように)。呼び出しに番号がない場合 (これは、実行が進むまでデバッグ モードがオンに切り替えられなかった場合に発生します)、これは「-」でマークされます。コンパイル済みコードには使用できません。
最上位は通常、コンパイルされた述語 prolog/0 であるため、これを使用して、独自の呼び出しスタックを検査し、サービスを開始するかどうかを決定する述語を作成できます。
rule2 :- ancestors(L), length(L,N), N<2, !, write('Don't call me'), fail.
rule2 :- 1<5.
現代のプロローグでは、祖先/1 述語はあまり見られなくなりました。ただし、次の行に沿ってシミュレートできます。エラーをスローするだけで、エラーがスタック トレースで装飾されている場合は、必要なものがすべて得られます。
ancestors(L) :- catch(sys_throw_error(ignore),error(ignore,L),true).
ただし、スタック削除の最適化によりスタックが削減され、祖先/1 によって返されるリストが削減される可能性があることに注意してください。
よろしくお願いします
PS: スタック削除の最適化は、ここで既に説明されています: [4] Warren, DHD (1983): An Abstract Prolog Instruction Set、Technical Note 309、SRI International、1983 年 10 月
Jekejeke Prolog に関する議論は、 http ://www.jekejeke.ch/idatab/doclet/prod/en/docs/10_pro08/13_press/03_bench/05_optimizations/03_stack.html にあります。