3

私は Prolog を初めて使用するため、次のタスクについてサポートが必要です。

私はプログラムを持っています:

do(save) :- save_bal(bad).
do(act) :- save_bal(good), inc(good).
do(comb) :- save_bal(good), inc(bad).
save_bal(good) :- savMoney(X), depPeople(Y), Min is Y * 1000, X >= Min.
save_bal(bad) :- not(save_bal(good)).
inc(good) :- earn(Z), depPeople(Y), MinE is 3000 + Y * 400, Z >= MinE.
inc(bad) :- not(inc(good)).
savMoney(30000).
earn(60000).
depPeople(4).

私の仕事はこのプログラムを書き直すことなので、30000、60000、4 という数字はユーザー入力によって設定されます。これどうやってするの?

私は試した:

:- read(A), savMoney(A).
:- read(B), earn(B).
:- read(C), depPeople(C).

しかし、それはうまくいきません。

誰かが私を正しい方向に向けることができますか?

前もって感謝します!

4

2 に答える 2

3

Prolog はホモイコニック言語 です。最初に取るべきステップは、どの述語がデータであり、どれがデータの論理制約であるかを宣言することです。

次に、ファイルの上部近くに (文体のヒントにすぎない) 宣言を追加します。

:- dynamic(savMoney/1).
:- dynamic(earn/1).
:- dynamic(depPeople/1).

次に、user_update_store/1 などのサービス述語を追加できます。

user_update_store(Entry) :-
  AccessValueCurr =.. [Entry, ValueCurr],
  (retract(AccessValueCurr) -> true ; ValueCurr = 0),
  format('enter value for ~s (current is ~w):', [Entry, ValueCurr]),
  read(NewValue),
  % validate it's a number etc...
  StoreNewValue =.. [Entry, NewValue],
  assertz(StoreNewValue).

これで、ユーザー インターフェイスを開始できます。

?- maplist(user_udpdate_store, [savMoney,earn,depPeople]).

このコードは、すべての (ISO 準拠の) Prolog で機能するはずです。注:私はそれをテストしませんでした...

HTH

于 2013-10-02T08:34:42.803 に答える
2

CapelliC は、私がこの怪物を入力するのに忙しかったときに、優れた (より良い) 回答を提供してくれました。実際、パラメーターを問題なく渡していたため、タイトルの質問に対処することにはなりませんでした。assertz/1代わりに、とについて書きましretract/1た。ただし、作成中にかなりの量を独学したので、参考になるかもしれません。

savMoney/1あなたのコード例では、述語, earn/1, depPeople/1'. We then have a number of rules that determine values based on these facts. A rule is of the form:-で宣言された 3 つのファクトがあります。, and which I sometimes read to myself as "<head> is true if <body> is true". We can think of a fact as a rule of the form:- true , e.g.,savMoney(30000) :- true.`、「true が true の場合、30000 は savMoney です」と読むことができます。(ちなみに、「savMoney」は貯蓄されたお金の略ですか?)

ディレクティブの形式は:- <body>.です。これは、プログラム (または世界) が真であるためにテストされなければならない規則のようなものです (これは、正確というよりも刺激的です。警告が表示されるだけです)。プロローグ ファイルを参照すると、プログラムの世界に新しいルール事実a :- \+ a.が追加されます。これらは、「not-a が true の場合、a は true」のような不可能でナンセンスなステートメントでさえあります1。その矛盾により、クエリを実行するとスタック オーバーフローが発生します?- a.が、プログラムは問題なくロードされます。ただし、ディレクティブは、検出された順序でプログラムがロードされている間に評価および解決する必要があります。

このプログラムは、インタープリターが参照すると、スタック オーバーフロー エラーをスローします。

a :- \+ a.
:- a.

undefined procedurea がデータベースに入力される前に a を証明するように指示されているため、このプログラムはエラーをスローします。

:- a.
a :- \+ a.

のようなディレクティブがある場合:- read(A), savMoney(A).、「ユーザー入力の値を A に読み取ってから、saveMoney を A に設定する」とは言いません。代わりに、「このプログラムがロードされた場合、A はユーザー入力から読み取られた値であり、 A は savMoney です」というようなことを言っています。プログラムを実行し、最初のプロンプト (通常のプロンプトは|) で 100 を入力するとします。何が起こるのですか?

  1. prolog は、変数 A を 100 で統一します。
  2. prolog は savMoney(100) を証明しようとします。
  3. 返信しますWarning: Goal (directive) failed: user:(read(_G2072),savMoney(_G2072))

これは、savMoney(30000) は true ですが、savMoney(100) はそうでないためです。ディレクティブはその本体の内容をアサートしません。プロローグにそれらの内容を証明するように指示するだけです。

あなたがやろうとしているのは、ユーザーが以前は知られていない事実をデータベースにアサートできるようにすることです。mbratch で示されているように、これには述語assertz/12を使用する必要があります。ただし、実行時に変更される予測は、標準の述語とは区別されます。

プログラムで再確立された述語を定義しようとすると、エラーが発生します。たとえば、次の宣言で構成されるファイルを調べます。

length(2, y).

次のエラーが表示されます。

ERROR: /Users/aporiac/myprolog/swi/studies/test.pl:18:
No permission to modify static procedure `length/2'
Defined at /opt/local/lib/swipl-6.2.6/boot/init.pl:2708

これは、「length/2」が静的であり、init.pl ファイルの 2708 行目で既に定義されていることを示しています。

で静的述語をアサートしようとすると、同じことが起こりますassertz/1assertz(savMoney(100))これは、swiplでクエリを実行して試すことができます。述語に関する新しい事実またはルールを追加するには、述語を動的であると宣言する必要があります。

これは で達成されdynamic/1ます。どの述語が動的としてカウントされるかをプロローグが確実に認識できるようにするために、 so 3のようなディレクティブを与えます。

:- dynamic savMoney/1.

それをファイルに追加した場合 (述語を定義する?- assertz(savMoney(100)).)、クエリを実行して新しいファクトをデータベースに追加できます。をクエリする?- savMoney(X)と、次のようになります。

X = 30000;
X = 100.

データベースに別のファクトを追加したため、X には 2 つの可能な値があります。

もちろん、あなたの場合、 に値を追加し続けるのではなく、値savMoney/1を更新して置き換えることができるようにしたいと考えています。

それにはretract/1必要があります (アサートされた述語がある時点で複数回出現する可能性があると思われる場合は、 を使用retractall/1してすべてのインスタンスをクリアできます)。これで、次のようなルールを記述できます。

set_saved(Amount) :-
    retract( savMoney(_) ),
    assertz( savMoney(Amount) ).

set_saved(Amount)savMoney(_)データベースから撤回および削除でき、新しいファクトsavMoney(Amount)をアサートできる場合は true です。

CapelliC が単純な入力インターフェイスを提供し、問題に対するより簡潔な解決策を提供していることを確認しましたが、有益な場合に備えて、サンプル プログラムの私のバージョンを示します。(実際にはプロンプトと入力を追加することはできませんでしたが、たとえば、クエリを?- set_saved(100)実行すると、期待どおりの結果が得られます)。

:- dynamic [ savMoney/1,
             earn/1,
             depPeople/1 ].


do(save) :- save_bal(bad).
do(act) :- save_bal(good), inc(good).
do(comb) :- save_bal(good), inc(bad).
save_bal(good) :- savMoney(X), depPeople(Y), Min is Y * 1000, X >= Min.
save_bal(bad) :- not(save_bal(good)).
inc(good) :- earn(Z), depPeople(Y), MinE is 3000 + Y * 400, Z >= MinE.
inc(bad) :- not(inc(good)).

savMoney(30000).
earn(60000).
depPeople(4).

set_saved(Amount) :-
    retract( savMoney(_) ),
    assertz( savMoney(Amount) ).

set_earned(Amount) :-
    retract( earn(_) ),
    assertz( earn(Amount) ).

set_people_in_department(Number) :-
    retract( depPeople(_) ),
    assertz( depPeople(Number) ).

report([Saved, Earned, People]) :-
    Saved   = savMoney(_) , Saved,
    Earned  = earn(_)     , Earned,
    People  = depPeople(_), People.

  1. \+/1は、swi-prolog の標準の否定演算子であり、not/1減価償却されています。

  2. assert/1は と同等で、 に有利に減価償却されassertz/1ます。asserta/1事実または節を、手元の述語の最初のインスタンスとしてassertz/1アサートし、それを最後としてアサートします。(データベースのマニュアルセクションを参照)。

  3. もちろん、これは私が以前に提案したディレクティブの解釈に反します。私の解釈は、ディレクティブで「通常の」述語を使用している場合に当てはまります。しかし、ほとんどの場合、モジュール宣言 ( :- module(name, [<list of exported predicates>]) やモジュール インポート ( ) などの特別な述語に使用されるディレクティブを目にします:- use_module([<list of modules>])

于 2013-10-02T10:49:19.443 に答える