我最近在Prolog中遇到以下问题:定义一个谓词avg_num/0
,它以交互方式提示用户输入一系列数字(或单词" stop"不带引号以结束流程)。该程序输出这些数字的平均值。
在Prolog终端/解释器中,程序应该像这样运行:
?- avg_sum.
?- Enter a number (or stop to end): 2.
?- Enter a number (or stop to end): |: 3.
?- Enter a number (or stop to end): |: 7.
?- Enter a number (or stop to end): |: stop.
The average is 4.
true.
我的想法是将值存储到列表中,然后使用以下代码计算该列表的平均数。
% finding the sum of numbers of a list
sumlist([],0).
sumlist([H|T],Sum):- sumlist(T,SumTail), Sum is H + SumTail .
% finding the average of the numbers in a list
average(List,A):- sumlist(List,Sum), length(List,Length), A is Sum / Length .
然后将问题简化为:如何将用户输入的数字存储到列表中?不知怎的,我觉得我需要在开始时初始化空列表,但我不知道在哪里放它。我尝试过以下代码(但这不完整):
avg_sum:- write('Enter a number (or stop to end): '), process(Ans).
process(Ans):- read(Ans),Ans \= "stop", append(X,[Ans],L).
% this part is still incomplete and incorrect.
似乎我需要初始化空列表,但我不知道在哪里。
答案 0 :(得分:1)
你几乎就在那里。正如您所说,您需要保留一个输入列表,然后在知道整个列表后进行最终计算。这样的列表(或保存中间数据的其他对象)通常称为累加器。
以下是实现此目的的一种方法。它基于两个辅助谓词,一个用于执行I / O部分,一个用于执行计算。
我们用空列表开始计算,如你所说。
avg_num :-
avg_num([], Average),
write('The average is '), write(Average), writeln('.').
(回想一下,在Prolog中你可以用不同的arities重载谓词名称,即avg_num/0
是avg_num/2
的单独谓词。)
现在avg_num/2
可以要求输入并将该输入的处理交给process/3
:
avg_num(Accumulator, Average) :-
write('Enter a number (or stop to end): '),
read(Answer),
process(Answer, Accumulator, Average).
仅在process/3
中,我们通过计算输入stop
时的平均值来消耗累加器,或者(如果与stop
不同)通过简单地将答案添加到累加器并继续
process(stop, Accumulator, Average) :-
average(Accumulator, Average).
process(Answer, Accumulator, Average) :-
dif(Answer, stop),
avg_num([Answer | Accumulator], Average).
请注意,列表中数字的顺序与计算平均值无关,因此我们可以在列表的前面添加输入,这比在最后附加更容易。
avg_num/2
和process/3
谓词之间的相互递归不一定容易理解,特别是因为名称选择不当。
在实践中,我会通过这样简化process/3
来摆脱avg_num/2
:
avg_num(Accumulator, Average) :-
write('Enter a number (or stop to end): '),
read(Answer),
( Answer = stop
-> average(Accumulator, Average)
; avg_num([Answer | Accumulator], Average) ).
答案 1 :(得分:1)
我会分出一个读取列表的谓词,然后处理列表。
这是在列表中读取的一种方式,直到结束语为End
:
% read_list_until
%
read_list_until(L, End) :-
( read_element(E, End)
-> L = [E|L1],
read_list_until(L1, End)
; L = []
).
read_element(E, End) :-
read(E),
dif(E, End).
这有以下行为:
2 ?- read_list_until(L, stop).
|: 1.
|: 2.
|: 3.
|: stop.
L = [1, 2, 3].
3 ?-
然后你可以使用标准的Prolog谓词来取平均值:
avg_list(L, Avg) :-
read_list_until(L, stop),
sum_list(L, Sum),
length(L, Num),
Avg is Sum / Num.