累积而在递归/回溯(Accumulating while in recursion/backtrac

2019-09-22 02:58发布

我碰到这个初学者的问题,我不知道如何解决此问题。 这里是我的代码:

worker( w1, d1, 2000 ) .    
worker( w2, d1, 2500 ) .
worker( w2, d2, 1000 ) .
worker( w3, d2, 2000 ) .
worker( w4, d2, 4000 ) .

% worker( W, D, S ) means that worker W works in department D and has salary S

department( d1, w2 ) .
department( d2, w4 ) .

% department( D, B ) means that worker B is director of department D(this is not important in this case)

我需要把所有的工资之和组成部门之一,这样的:

?- department_costs( d1 , T ) .
T = 4500;
no
?- department_costs( D, T ) .
D = d1
T = 4500;
D = d2
T = 7000;
no
?- department_costs( d3 , T ) .
no

我尝试这样做:

department_costs( D, T ):- worker( _X, D, T1 ), T is T1.

而我得到这个:

?- department_costs( o1, T ).
T=2000;
T=2500;
no

现在我需要总结T + T的总成本,但我不知道该怎么做。 我想解决这个问题,而无需使用的findall / SETOF / bagof。

编辑:

我试着用的findall:

sumL([], 0).
sumL([G|R], S):-
   sumL(R, S1),
   S is S1 + G.

department_costs( D, T ):-
   findall(P, worker( _X, D, P ), R ),
   sumL(R, S),
   T=S.

它的工作原理罚款department_costs(D1,T),以及department_costs(D2,T),但是当我进入department_costs(d,T)。 我得到这个:

 department_costs( D, T ).
 O=_h159
 T=11500

它应该是这样的:

 ?- department_costs( D, T ) .
 D = d1
 T = 4500;
 D = d2
 T = 7000;

谁能告诉现在什么是问题呢?

Answer 1:

想要解决这个问题没有findall/3只会导致在重新编码的不良企图说findall/3 。 如果你真的想跳过findall/3 ,代表你的数据以不同的方式,例如:

workers([w1-d1-2000, w2-d1-2500, w2-d2-1000, w3-d2-2000, w4-d2-4000]).
departments([d1-w2, d2-w4]).

在此格式,你将能够使用递归和列表处理技术,实现了良好的效果。 在前面的一个,你将不得不去与任何数据库操作和/或全局变量。 没有真正的Prolog十岁上下。

为了您的编辑,问题是,你使用findall/3 ,和findall/3将会给大家的一个变量,你感兴趣的效果,反而会不准确,导致这些结果的绑定。

尝试bagof/3 ,而不是:

bagof(S, W^worker( W, D, S ), R ).

看这男人页 (即使是SWI,这些都是ISO Prolog的谓词反正)了解更多信息。



Answer 2:

图书馆( 总 )是为了解决正是这样那样的问题。 这是值得学习。

department_costs( D, T ) :- aggregate_all(sum(C), worker( _, D, C ), T).

编辑

XSB有“ 制表汇总谓语 ”应该让你有效地解决你的问题。



Answer 3:

原油的种类,并收回用于每一个工人的事实,但将这样的伎俩:

department_costs(D,T) :- worker(X,D,T1), retract(worker(X,D,T1)), department_costs(D,T2), T is T1+T2).
department_costs(_,0).

一个破坏性较小的替代办法是绕过迄今使用的员工名单中,验证任何将要使用的工人不在列表中,和新使用的工作添加到列表中的递归调用。 (我想你可以,而不是仅仅在条款的最后重新断言缩回事实上,递归调用返回后,但感觉真的哈克。)



Answer 4:

我没有测试过这一点,但这个想法是你积累你已经算工人。 我真的不喜欢它,虽然,如果我发现超过两分钟,这一点我敢肯定,你可以做一个更声明的方式,而不邪削减更多。

department_sum(S, D) :- 
        department_sum_agg([], S, D).

department_sum_agg(Workers, S, D) :- 
    worker(X,D,SX), 
    \+ member(X, Workers), !,
    department_sum_agg([X|Workers], SRest, D),
    S is SX + SRest.

department_sum_agg(_, 0, _).


文章来源: Accumulating while in recursion/backtracking
标签: prolog