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

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

findall_n(_限界度数,_蒐集項,_目標,_蒐集項ならび) :-
メッセージキューを生成し番号ならびを詰める(_限界度数,_キュー番号),
'目標を実行して蒐集項ならびを得る'(_限界度数,_キュー番号,_蒐集項,_目標,_蒐集項ならび).

'目標を実行して蒐集項ならびを得る'(_限界度数,_キュー番号,_蒐集項,_目標,_蒐集項ならび) :-
findall(_蒐集項,(
call(_目標),
thread_get_message(_キュー番号,_項),
( _項 = _限界度数,!,true;true)),_蒐集項ならび).

メッセージキューを生成し番号ならびを詰める(_限界度数,_キュー番号) :-
message_queue_create(_キュー番号),
thread_create(度数(_限界度数,_キュー番号),_,[]).

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

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