3

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

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.

它适用于部门成本(d1,T)和部门成本(d2,T),但是当我输入部门成本(D,T)时。我明白了:

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

它应该是这样的:

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

有人可以告诉现在是什么问题吗?

4

4 回答 4

5

library( aggregate ) 旨在解决此类问题。值得学习。

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

编辑

XSB 有“ Tableling Aggregate Predicates ”,可以让你有效地解决你的问题。

于 2012-09-04T10:32:23.377 回答
5

想要解决这个问题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-ish。

对于您的编辑,问题在于您使用findall/3,这findall/3将为您提供您感兴趣的一个变量的所有结果,但不会精确导致这些结果的绑定。

请尝试bagof/3

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

并查看此手册页(即使它是 SWI,无论如何这些都是 ISO Prolog 谓词)以获取更多信息。

于 2012-09-04T00:27:10.503 回答
1

有点粗鲁,并收回了使用的每个工人事实,但会成功:

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

一个破坏性较小的替代方法是传递到目前为止使用的工人列表,验证任何将要使用的工人不在列表中,并将新使用的工人添加到递归调用的列表中。(我想你可以改为在递归调用返回后,在子句末尾重新断言撤回的事实,但这感觉真的很糟糕。)

于 2012-09-03T23:59:09.137 回答
1

我没有对此进行测试,但想法是你积累了你已经计算过的工人。不过,我真的不喜欢它,如果我为此找到超过几分钟的时间,我相信你可以以一种更具声明性的方式做到这一点,而不会受到邪恶的削减。

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, _).
于 2012-09-06T11:24:12.443 回答