2012-09-03 120 views
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总和c osts,但我不知道该怎么做。我想用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; 

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

回答

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

而且看到这个man page(即使是SWI,这些都是ISO Prolog的谓词反正)了解更多信息。

+0

我会尝试的findall然后,我会后我尝试 – user1598696

+0

我做了关于你提出 – m09

+0

感谢代码的编辑对我的回答它的工作原理: ) – user1598696

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

一个破坏性较小的替代办法是绕过迄今使用的员工名单中,验证有关的任何工人要使用的列表不在列表中,并将新使用的worker添加到递归调用的列表中。 (我想你可以在递归调用返回之后重新声明子句末尾的缩进事实,但这种感觉真的很乱。)

+0

不为我工作:( – user1598696

5

库(aggregate)意在准确地解决这样的问题。值得研究。

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

编辑

XSB有 'Tabling Aggregate Predicates' 应该让你有效地解决你的问题。

+0

我要使用XSB序言,我希望有聚集库但不存在:( – user1598696

+2

我见过SWI-Prolog标记,对不起... XSB应该有一些更基本的聚合方式,因为它实现了**制表**,我会尝试在文档中找到一些东西。 – CapelliC

+0

非常感谢您的帮助! – user1598696

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, _). 
+0

对于查询'department_sum(S,D)'结果将取决于'worker/3'的答案顺序,如果用事实定义,则只考虑第一个事实的部门...... – false