我是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).
但这不起作用。
有人能指出我正确的方向吗?
提前致谢!
答案 0 :(得分:3)
Prolog是homoiconic language,那么你应该采取的第一步是声明哪个谓词是数据,哪些(只是说)对数据的逻辑约束。
然后,在文件的顶部附近添加(只是样式提示)声明
:- 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
答案 1 :(得分: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。,我们可以读作&#34; 30000是savMoney如果true是真的&#34;,并且true是真的或者我们都被搞砸了。 (顺便说一句,&#39; savMoney&#39;省钱?)
指令的格式为:- <body>.
。这就像一个规则,必须进行测试,以使程序(或世界)成为现实(这比准确更令人回味,因为,正如您所见,当指令失败时,整个程序世界不是是的,我们只是得到一个警告)。当我们查阅prolog文件时,我们将新的规则和事实添加到我们的程序世界中,这些甚至可能是不可能的无意义语句,如a :- \+ a.
&#34 ;如果不是-a是真的,则a为真&#34; 1 。如果你查询?- a.
,那个矛盾将导致堆栈溢出,但程序将加载正常。但是,当程序按照遇到的顺序加载时,必须评估和解决指令:
当解释器查询时,该程序将抛出堆栈溢出错误。
a :- \+ a.
:- a.
此程序将抛出undefined procedure
错误,因为它被指示在输入数据库之前证明a。
:- a.
a :- \+ a.
当我们有:- read(A), savMoney(A).
之类的指令时,它不会说&#34;将用户输入的值读入A,然后将saveMoney设置为A&#34;。相反,它说的更像是,&#34;如果加载了这个程序,则A是从用户输入读入的值, A是savMoney。&#34;假设您运行程序并在第一个提示符处输入100(普通提示符为|
)。会发生什么?
Warning: Goal (directive) failed: user:(read(_G2072),savMoney(_G2072))
。这是因为,虽然savMoney(30000)是真的,但savMoney(100)却不是。指令不会断言其正文的内容,它只会告诉prolog来证明这些内容。
您要做的是允许用户将以前未知的事实断言到数据库中。如mbratch所示,这需要使用谓词assertz/1
2 。但是,预测在运行期间进行更改会与标准谓词区分开来。
如果您尝试在程序中定义重新建立的谓词,则会收到错误。例如,查阅包含以下声明的文件:
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
这告诉我们&#39;长度/ 2&#39;是 static ,它已经在第2708行的init.pl文件中定义。
如果您尝试使用assertz/1
声明静态谓词,也会发生同样的情况。您可以通过在swipl中查询assertz(savMoney(100))
来尝试此操作。为了添加关于谓词的新事实或规则,我们必须将谓词声明为动态。
这是通过dynamic/1
完成的。为了确保prolog知道哪些谓词被认为是动态的,我们给它一个像 3 这样的指令:
:- dynamic savMoney/1.
如果您已将其添加到文件中(之前定义谓词),则可以查询?- assertz(savMoney(100)).
以将新事实添加到数据库中。现在,如果您查询?- savMoney(X)
,那么您将获得
X = 30000;
X = 100.
X现在有两个可能的值,因为我们已经在数据库中添加了另一个事实。
当然,在您的情况下,您不想继续向savMoney/1
添加值,您希望能够更新并替换该值。
这需要retract/1
(如果您认为在某个时刻可能会多次添加断言的谓词,那么您可以使用retractall/1
清除所有实例) 。现在我们可以编写如下规则:
set_saved(Amount) :-
retract( savMoney(_) ),
assertz( savMoney(Amount) ).
如果set_saved(Amount)
可以从数据库中撤消并删除,并且可以声明新事实savMoney(_)
,则 savMoney(Amount)
为真。
我刚刚看到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
是swi-prolog和not/1
is depreciated中的标准否定运算符。
assert/1
相当于assertz/1
,并赞成使用asserta/1
。 assertz/1
将事实或子句断言为手头谓词的第一个实例,而:- module(name, [<list of exported predicates>]
将其断言为最后一个。 (参见Database上的手册部分)。
当然,这违背了我之前建议的指令的解释。我的解释适合您使用&#39; normal&#39;指令中的谓词。但是,大多数情况下,我们会看到用于特殊谓词的指令,如模块声明(:- use_module([<list of modules>])
)或模块导入({{1}})。