123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182openCore_kernelopenDeferred_stdmoduleDeferred=Deferred1(* [fold_mapi ?how t ~init ~mapi_f ~fold_f] is a more efficient version of:
{[
fold ~init ~f:(fun b a -> return (fold_f b a)) (mapi t ?how ~f:mapi_f) ]}
It avoids creating the intermediate sequence that would result from [mapi], and
allows the [fold] to proceed concurrently with the [mapi], so that one can accumulate
the result as soon as possible, possibly avoiding creating an intermediate structure
(e.g. [iteri] and [filter_map] uses [fold_mapi] to do this). *)letfold_mapi(typeabc)?(how=`Sequential)(t:aSequence.t)~(init:c)~(mapi_f:int->a->bDeferred.t)~(fold_f:c->b->c):cDeferred.t=matchhowwith|`Sequential->letrecloopit(c:c)=matchSequence.nexttwith|None->returnc|Some(a,t)->let%bindb=mapi_fiainloop(i+1)t(fold_fcb)inloop0tinit|`Parallel->letrecloopit(c:cDeferred.t)=matchSequence.nexttwith|None->c|Some(a,t)->loop(i+1)t(let%bindb=mapi_fiainlet%mapc=cinfold_fcb)inloop0t(returninit)|`Max_concurrent_jobsmax_concurrent_jobs->letthrottle=Throttle.create~max_concurrent_jobs~continue_on_error:falsein(* [loop] forces the input sequence and enqueues a throttle job only if there is
capacity available. *)letrecloopit(c:cDeferred.t)=let%bind()=Throttle.capacity_availablethrottleinmatchSequence.nexttwith|None->c|Some(a,t)->loop(i+1)t(let%bindb=Throttle.enqueuethrottle(fun()->mapi_fia)inlet%mapc=cinfold_fcb)inloop0t(returninit);;letfoldit~init~f=Sequence.delayed_foldt~init:(0,init)~f:(fun(i,b)a~k->let%bindb=fibaink(i+1,b))~finish:(fun(_,b)->returnb);;(* [fold] is not implemented in terms of [foldi] to save the intermediate closure
allocation. *)letfoldt~init~f=Sequence.delayed_foldt~init~f:(funba~k->fba>>=k)~finish:return;;letallt=let%mapres=foldt~init:[]~f:(funaccumd->let%mapa=dina::accum)inSequence.of_list(List.revres);;letall_unitt=foldt~init:()~f:(fun()v->v)letfind_mapit~f=letrecfind_mapit~fi=matchSequence.nexttwith|None->returnNone|Some(v,rest)->(match%bindfivwith|None->find_mapirest~f(i+1)|Some_assome->returnsome)infind_mapit~f0;;letfindit~f=find_mapit~f:(funielt->let%mapb=fieltinifbthenSome(i,elt)elseNone);;letfindt~f=find_mapit~f:(fun_elt->let%mapb=feltinifbthenSomeeltelseNone);;letexistsit~f=match%mapfind_mapit~f:(funielt->let%mapb=fieltinifbthenSome()elseNone)with|Some()->true|None->false;;letfor_allit~f=match%mapfind_mapit~f:(funielt->let%mapb=fieltinifnotbthenSome()elseNone)with|Some()->false|None->true;;letiteri?howt~f:unitDeferred.t=fold_mapi?howt~mapi_f:f~init:()~fold_f:(fun()()->());;letmapi?howt~f=let%mapbs=fold_mapi?howt~mapi_f:(funia->fia)~init:[]~fold_f:(funbsb->b::bs)inSequence.of_list(List.revbs);;(* [filter_mapi] is implemented using [fold_mapi] rather than [map] so that we never need
to keep a long stream of intermediate [None] results in the accumulator, only to later
filter them all out. *)letfilter_mapi?howt~f=let%mapbs=fold_mapit?how~mapi_f:(funia->fia)~init:[]~fold_f:(funbsmaybe_v->matchmaybe_vwith|None->bs|Someb->b::bs)inSequence.of_list(List.revbs);;letconcat_mapi?howt~f=mapi?howt~f>>|Sequence.concatletfilteri?howt~f=filter_mapi?howt~f:(funia->match%mapfiawith|true->Somea|false->None);;letiter?howt~f=iteri?howt~f:(fun_a->fa)letmap?howt~f=mapi?howt~f:(fun_a->fa)letfilter?howt~f=filteri?howt~f:(fun_a->fa)letfilter_map?howt~f=filter_mapi?howt~f:(fun_a->fa)letconcat_map?howt~f=concat_mapi?howt~f:(fun_a->fa)letfind_mapt~f=find_mapit~f:(fun_a->fa)letexistst~f=existsit~f:(fun_a->fa)letfor_allt~f=for_allit~f:(fun_a->fa)letinit?hown~f=map?how(Sequence.initn~f:Fn.id)~f