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)

次のように、部門の1つからすべての給与の合計を取得する必要があります。

?- 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;

誰かが今何が問題なのか教えてもらえますか?

4

4 に答える 4

5

library(aggregate)は、まさにそのような問題を解決することを目的としています。勉強する価値があります。

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

編集

XSBには、問題を効率的に解決できるようにする「 TablingAggregatePredicates 」があります。

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

この形式では、再帰とリスト処理の手法を使用して、良好な結果を得ることができます。前のものでは、データベース操作またはグローバル変数、あるいはその両方を使用する必要があります。本当にプロローグっぽくない。

編集の場合、問題はを使用するfindall/3ことfindall/3です。これにより、関心のある1つの変数のすべての結果が得られますが、それらの結果につながるバインディングは正確にはなりません。

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 に答える