Prolog:将用户输入作为参数传递

时间:2013-10-01 18:46:13

标签: io prolog

我是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).

但这不起作用。

有人能指出我正确的方向吗?

提前致谢!

2 个答案:

答案 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/1retract/1的文章。然而,我在编写它的过程中自学了相当多的东西,你也可能会发现它具有丰富的信息。

在您的示例代码中,我们使用谓词savMoney/1earn/1depPeople/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(普通提示符为|)。会发生什么?

  1. prolog将变量A与100结合使用。
  2. prolog试图证明savMoney(100)。
  3. 它回复了Warning: Goal (directive) failed: user:(read(_G2072),savMoney(_G2072))
  4. 这是因为,虽然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. \+/1是swi-prolog和not/1 is depreciated中的标准否定运算符。

    2. assert/1相当于assertz/1,并赞成使用asserta/1assertz/1将事实或子句断言为手头谓词的第一个实例,而:- module(name, [<list of exported predicates>]将其断言为最后一个。 (参见Database上的手册部分)。

    3. 当然,这违背了我之前建议的指令的解释。我的解释适合您使用&#39; normal&#39;指令中的谓词。但是,大多数情况下,我们会看到用于特殊谓词的指令,如模块声明(:- use_module([<list of modules>]))或模块导入({{1}})。