このディレクトリの索引
#  
#  目標を限界度数成功させて指定した蒐集項をならびとして得る
#  


目標を限界度数成功させて指定した蒐集項をならびとして得る(_限界度数,_蒐集項,_目標,_蒐集項ならび) :-
        findall_n(_限界度数,_蒐集項,_目標,_蒐集項ならび).

findall_n(_限界度数,_蒐集項,_目標,_蒐集項ならび) :-
        message_queue_create(_キュー番号),
        (   '子スレッドで、生成された度数を、限界度数に達したら0をキューに送る'(_限度度数,_キュー番号);
            キューから限界度数を示す0を受信するまで目標を成功させて蒐集項ならびを得る(_蒐集項,_目標,_キュー番号,_蒐集項ならび)).

キューから限界度数を示す0を受信するまで目標を成功させて蒐集項ならびを得る(_蒐集項,_目標,_キュー番号,_蒐集項ならび) :-
        findall(_蒐集項,(
                    thread_get_message(_キュー番号,_項),
                    ( _項 = 0,!,fail;call(_目標))),
                _蒐集項ならび).


'子スレッドで、生成された度数を、限界度数に達したら0をキューに送る'(_限度度数,_キュー番号) :-
        thread_create(度数(_限界度数,_キュー番号),_,[]).

度数(_限界度数,_キュー番号) :-
        between(1,_限界度数,_度数),
        _剰余 is _度数 mod ( _限界度数 + 1 ),
        thread_send_message(_キュー番号,_剰余),
        _度数 = _限界度数.




%  
%  先にlength/2等で解の枠が決まっている場合があるが、
%  findall/3述語だと、その枠を無視して、全解を蒐集して、
%  その上で第三引数のならびとの単一化を試みようとする。
%  目標の解が1000万個というように多量の場合は、
%  スタックオーバーフローが生じてエラーとなって終了する。
%  
%  これに対して、この述語は子スレッドを作り出して、ここで
%  本来は現在の解数を数えさせてキュー経由で親スレッドは
%  これを受信する。この為には親スレッドから子スレッドに解が
%  取れたことを送信するためのキューが必要であるがここでは
%  それを省略した。子から親への片方向の通信になっている。
%  
%  子スレッドは1から解の限界数まで整数をキューに一気に詰め、
%  さらに、終了の合図である0を詰める。親スレッドは目標が
%  達成される度にキューから一つ度数情報を取り出す。
%  解の数が限界数に達した時に子スレッドが既に送信してあった
%  0を受信することになり、親スレッドのfindall_n/4の目標内の
%  カットが発動されて強制的にfindall_n/4を終了させることが
%  できる。
%  
%  ここではfindall/3を対象にしているがsetof/3やbagof/3も
%  全く同様の問題があるし、解決策も同じである。