このディレクトリの索引
#  
#  Prologの集約問題
#  述語体重が定義されている時、各節で定義されているメンバーの
#  平均体重を求めるという問題だ。
#  
#  体重(島田,57).
#  体重(服部,65).
#  体重(内山,70).
%    
%  最初に最も普通の定義を示す。

体重(島田,57).
体重(服部,65).
体重(内山,70).

平均体重(_平均体重) :-
        findall(_体重,体重(_,_体重),_メンバーの体重リスト),
        length(_メンバーの体重リスト,_人数),
        sum_list(_メンバーの体重リスト,_体重合計),
        _平均体重 is _体重合計 / _人数.

%
%  Prologを単位節データとして使用する場合、以下のfindavg/3を使います。
%  findavg/3 をライブラリに加えておきます。
%

体重(島田,57).
体重(服部,65).
体重(内山,70).

平均体重(_平均体重) :-
        findavg(_体重,体重(_,_体重),_平均体重).

findavg(_集約項,_項,_算術平均) :-
        findall(_集約項,_項,_値リスト),
        sum_list(_値リスト,_合計値),
        length(_値リスト,_リストの長さ),
        _算術平均 is _合計値 / _リストの長さ,!.

%
%
%  次の定義は体重データベースの構造を変更してしまう対処です。
%  定義自体を一引数増やして、有向グラフの述語表現にしてみます。
%

体重(島田,服部,57).
体重(服部,内山,65).
体重(内山,島田,70).

平均体重(_平均体重) :-
        体重(_最初の人,_次の人,_最初の人の体重),
        合計体重(_次の人,_最初の人,_人数,_合計体重),
        _平均体重 is _合計体重 / _人数,!.

合計体重(_最初の人,_最初の人,1,_最初の人の体重) :-
        体重(_最初の人,_,_最初の人の体重).
合計体重(_前の人,_最初の人,_人数,_合計体重) :-
        体重(_前の人,_次の人,_体重),
        合計体重(_次の人,_最初の人,_人数_1,_合計体重_1),
        _合計体重 is _体重 + _合計体重_1,
        _人数 is _人数_1 + 1.

%
%  直ぐにわかることは、同姓が出てくると困る。
%  それで、普通は名前でノードを構成することはせず、
%  所謂、IDを振ります。この振り方が大問題となりますが。
%  ここではIDは a,b,8 を使っています。
%

体重(a,b,島田,57).
体重(b,8,服部,65).
体重(8,a,内山,70).

平均体重(_平均体重) :-
        体重(_id,_id_1,_,_体重),
        合計体重(_id_1,_id,_人数,_合計体重),
        _平均体重 is _合計体重 / _人数,!.

合計体重(_id,_id,1,_体重) :-
        体重(_id,_,_,_体重),!.
合計体重(_id_1,_id,_人数,_合計体重) :-
        体重(_id_1,_id_2,_,_体重),
        合計体重(_id_2,_id,_人数_1,_合計体重_1),
        _合計体重 is _体重 + _合計体重_1,
        _人数 is _人数_1 + 1.

%
%  もしIDが1を先頭とする連続した整数であることを維持できるのなら
%  

体重(1,島田,57).
体重(2,服部,65).
体重(3,内山,70).

平均体重(_平均体重) :-
        合計体重(1,_人数,_合計体重),
        _平均体重 is _合計体重 / _人数.

合計体重(_id,_人数,_合計体重) :-
        体重(_id,_,_体重),
        _id_2 is _id + 1,
        合計体重(_id_2,_人数_2,_合計体重_2),
        _人数 is _人数_2 + 1,
        _合計体重 is _体重 + _合計体重_2,!.
合計体重(_,0,0).