12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139(* This file provides useful / reasonable visitor methods for many of the
built-in types of OCaml. *)(* The classes defined in this file are automatically inherited by
auto-generated visitors. If this is not desired, this behavior can be
turned off at generation time by specifying [nude = true]. *)(* Some of the code in this file can be (or has been) auto-generated by
the [visitors] package itself: see [test/VisitorsRuntimeBootstrap].
To avoid a complicated process and to facilitate code review, we
keep this code under manual control in this file. *)(* -------------------------------------------------------------------------- *)(* For compatibility with OCaml 4.02, we take the type [('a, 'b) result] from
the package [result]. This type appeared in the standard library in OCaml
4.03. *)openResult(* -------------------------------------------------------------------------- *)(* [array_equal eq xs1 xs2] tests whether the arrays [xs1] and [xs2] have the
same components. The arrays must have the same length. The components are
compared using [eq]. *)letrecarray_equaleqinxs1xs2=i=n||letx1=Array.unsafe_getxs1iandx2=Array.unsafe_getxs2iineqx1x2&&array_equaleq(i+1)nxs1xs2letarray_equaleqxs1xs2=letn=Array.lengthxs1inassert(Array.lengthxs2=n);array_equaleq0nxs1xs2(* -------------------------------------------------------------------------- *)(* An exception used at arity 2 and above. *)exceptionStructuralMismatchletfail()=raiseStructuralMismatchletwrapft=tryft;truewithStructuralMismatch->falseletwrap2ft1t2=tryft1t2;truewithStructuralMismatch->false(* -------------------------------------------------------------------------- *)(* A virtual base class for monoids. *)classvirtual['s]monoid=objectmethodprivatevirtualzero:'smethodprivatevirtualplus:'s->'s->'send(* -------------------------------------------------------------------------- *)(* Common monoids. *)class['s]addition_monoid=objectinherit['s]monoidmethodprivatezero=0methodprivateplus=(+)endclass['s]unit_monoid=objectinherit['s]monoidmethodprivatezero=()methodprivateplus()()=()end(* -------------------------------------------------------------------------- *)(* Visitor methods for the primitive types. *)(* Must the methods below be declared polymorphic in ['env]? The fact is, they
ARE polymorphic in ['env], because they do not extend it or look it up.
By declaring them polymorphic, we gain in generality: e.g., [visit_list]
can be called by two visitor methods which happen to have different types
of environments. (This happens in alphaLib, where visitor methods for terms
and patterns manipulate different types of environments.)
However, by declaring them polymorphic, we also lose some generality, as we
PREVENT users from overriding these methods with code that extends or looks
up the environment.
Here, it seems reasonable to take both the gain and the loss, and declare
these methods polymorphic.
We could give the user a choice by providing multiple base classes, but that
would messy. Note that, when using [@@deriving visitors { ... }], the user
does have a choice whether the generated methods should be polymorphic in
['env]. *)(* -------------------------------------------------------------------------- *)(* [iter] *)class['self]iter=object(self)methodprivatevisit_array:'env'a.('env->'a->unit)->'env->'aarray->unit=funfenvxs->(* For speed, we inline [Array.iter]. Chances are, we save a closure
allocation, as using [Array.iter] would require us to build [f env]. *)fori=0toArray.lengthxs-1dofenv(Array.unsafe_getxsi)donemethodprivatevisit_bool:'env.'env->bool->unit=fun__->()methodprivatevisit_bytes:'env.'env->bytes->unit=fun__->()methodprivatevisit_char:'env.'env->char->unit=fun__->()methodprivatevisit_float:'env.'env->float->unit=fun__->()methodprivatevisit_int:'env.'env->int->unit=fun__->()methodprivatevisit_int32:'env.'env->int32->unit=fun__->()methodprivatevisit_int64:'env.'env->int64->unit=fun__->()methodprivatevisit_lazy_t:'env'a.('env->'a->unit)->'env->'aLazy.t->unit=funfenv(lazyx)->fenvxmethodprivatevisit_list:'env'a.('env->'a->unit)->'env->'alist->unit=funfenvxs->matchxswith|[]->()|x::xs->fenvx;self#visit_listfenvxsmethodprivatevisit_nativeint:'env.'env->nativeint->unit=fun__->()methodprivatevisit_option:'env'a.('env->'a->unit)->'env->'aoption->unit=funfenvox->matchoxwith|None->()|Somex->fenvxmethodprivatevisit_ref:'env'a.('env->'a->unit)->'env->'aref->unit=funfenvrx->fenv!rxmethodprivatevisit_result:'env'a'e.('env->'a->unit)->('env->'e->unit)->'env->('a,'e)result->unit=funfgenvr->matchrwith|Oka->fenva|Errorb->genvbmethodprivatevisit_string:'env.'env->string->unit=fun__->()methodprivatevisit_unit:'env.'env->unit->unit=fun__->()end(* -------------------------------------------------------------------------- *)(* [map] *)class['self]map=object(self)methodprivatevisit_array:'env'a'b.('env->'a->'b)->'env->'aarray->'barray=funfenvxs->Array.map(fenv)xs(* We could in principle inline [Array.map] so as to avoid allocating
the closure [f env]. That would be a bit painful, though. Anyway,
in [flambda] mode, the compiler might be able to do that for us. *)methodprivatevisit_bool:'env.'env->bool->bool=fun_x->xmethodprivatevisit_bytes:'env.'env->bytes->bytes=fun_x->xmethodprivatevisit_char:'env.'env->char->char=fun_x->xmethodprivatevisit_float:'env.'env->float->float=fun_x->xmethodprivatevisit_int:'env.'env->int->int=fun_x->xmethodprivatevisit_int32:'env.'env->int32->int32=fun_x->xmethodprivatevisit_int64:'env.'env->int64->int64=fun_x->xmethodprivatevisit_lazy_t:'env'a'b.('env->'a->'b)->'env->'aLazy.t->'bLazy.t=funfenvthx->(* We seem to have two options: either force the suspension now
and rebuild a trivial suspension, or build now a suspension
that will perform the traversal when forced. We choose the
latter, which seems more interesting. If this is not the
desired behavior, it can of course be overridden. *)lazy(fenv(Lazy.forcethx))methodprivatevisit_list:'env'a'b.('env->'a->'b)->'env->'alist->'blist=funfenvxs->matchxswith|[]->[]|x::xs->letx=fenvxinx::self#visit_listfenvxsmethodprivatevisit_nativeint:'env.'env->nativeint->nativeint=fun_x->xmethodprivatevisit_option:'env'a'b.('env->'a->'b)->'env->'aoption->'boption=funfenvox->matchoxwith|None->None|Somex->Some(fenvx)methodprivatevisit_ref:'env'a'b.('env->'a->'b)->'env->'aref->'bref=funfenvrx->ref(fenv!rx)methodprivatevisit_result:'env'a'b'e'f.('env->'a->'b)->('env->'e->'f)->'env->('a,'e)result->('b,'f)result=funfgenvr->matchrwith|Oka->Ok(fenva)|Errorb->Error(genvb)methodprivatevisit_string:'env.'env->string->string=fun_x->xmethodprivatevisit_unit:'env.'env->unit->unit=fun_x->xend(* -------------------------------------------------------------------------- *)(* [endo] *)class['self]endo=object(self)(* We might wish to inherit from [map] and override only those methods where
a physical equality check is needed. Yet, we cannot do that, because some
methods, like [visit_list], have more restrictive types in this class than
in the class [map]. *)(* It may seem fishy to use an [endo] visitor at type [array], but one never
knows -- maybe the user wants this. Maybe she is using an array as an
immutable data structure. *)methodprivatevisit_array:'env'a.('env->'a->'a)->'env->'aarray->'aarray=funfenvxs->letxs'=Array.map(fenv)xsinifarray_equal(==)xsxs'thenxselsexs'methodprivatevisit_bool:'env.'env->bool->bool=fun_x->xmethodprivatevisit_bytes:'env.'env->bytes->bytes=fun_x->xmethodprivatevisit_char:'env.'env->char->char=fun_x->xmethodprivatevisit_float:'env.'env->float->float=fun_x->xmethodprivatevisit_int:'env.'env->int->int=fun_x->xmethodprivatevisit_int32:'env.'env->int32->int32=fun_x->xmethodprivatevisit_int64:'env.'env->int64->int64=fun_x->xmethodprivatevisit_lazy_t:'env'a.('env->'a->'a)->'env->'aLazy.t->'aLazy.t=funfenvthx->(* We could use the same code as in [map], which does not preserve sharing.
Or, we can force the suspension now, compute [x'], and if [x] and
[x'] coincide, then we can return the original suspension (now
forced), so as to preserve sharing. We choose the latter behavior. If
this is not the desired behavior, it can of course be overridden. *)letx=Lazy.forcethxinletx'=fenvxinifx==x'thenthxelselazyx'methodprivatevisit_list:'env'a.('env->'a->'a)->'env->'alist->'alist=funfenvthis->matchthiswith|[]->[]|x::xs->letx'=fenvxinletxs'=self#visit_listfenvxsinifx==x'&&xs==xs'thenthiselsex'::xs'methodprivatevisit_nativeint:'env.'env->nativeint->nativeint=fun_x->xmethodprivatevisit_option:'env'a.('env->'a->'a)->'env->'aoption->'aoption=funfenvox->matchoxwith|None->None|Somex->letx'=fenvxinifx==x'thenoxelseSomex'(* It probably does not make sense to use an [endo] visitor at type
[ref], but one never knows -- maybe the user wants this. Anyway,
it is consistent with the behavior of [endo] visitors at mutable
record types. *)methodprivatevisit_ref:'env'a.('env->'a->'a)->'env->'aref->'aref=funfenvrx->letx=!rxinletx'=fenvxinifx==x'thenrxelserefx'methodprivatevisit_result:'env'a'e.('env->'a->'a)->('env->'e->'e)->'env->('a,'e)result->('a,'e)result=funfgenvr->matchrwith|Oka->leta'=fenvainifa==a'thenrelseOka'|Errorb->letb'=genvbinifb==b'thenrelseErrorb'methodprivatevisit_string:'env.'env->string->string=fun_x->xmethodprivatevisit_unit:'env.'env->unit->unit=fun_x->xend(* -------------------------------------------------------------------------- *)(* [reduce] *)(* For arrays and lists, we use [fold_left] instead of a natural (bottom-up)
fold. The order in which the elements are traversed is the same either way
(namely, left-to-right) but the manner in which the [plus] operations are
associated is not the same, so the [plus] operator should be associative.
We could go back to a natural fold, but we would lose tail recursion. *)classvirtual['self]reduce=object(self:'self)inherit['s]monoidmethodprivatevisit_array:'env'a.('env->'a->'s)->'env->'aarray->'s=funfenvxs->Array.fold_left(funsx->self#pluss(fenvx))self#zeroxs(* We might wish to inline [Array.fold_left] and save a closure
allocation. That said, in flambda mode, the compiler might be
able to do that automatically. *)methodprivatevisit_bool:'env.'env->bool->'s=fun_env_->self#zeromethodprivatevisit_bytes:'env.'env->bytes->'s=fun_env_->self#zeromethodprivatevisit_char:'env.'env->char->'s=fun_env_->self#zeromethodprivatevisit_float:'env.'env->float->'s=fun_env_->self#zeromethodprivatevisit_int:'env.'env->int->'s=fun_env_->self#zeromethodprivatevisit_int32:'env.'env->int32->'s=fun_env_->self#zeromethodprivatevisit_int64:'env.'env->int64->'s=fun_env_->self#zeromethodprivatevisit_lazy_t:'env'a.('env->'a->'s)->'env->'aLazy.t->'s=funfenv(lazyx)->fenvxmethodprivatevisit_list:'env'a.('env->'a->'s)->'env->'alist->'s=funfenvxs->self#list_fold_leftfenvself#zeroxs(* The above line is equivalent to the following: *)(* List.fold_left (fun s x -> self#plus s (f env x)) self#zero xs *)(* By using the auxiliary method [list_fold_left] instead of calling
the library function [List.fold_left], we save a closure allocation,
at least in non-flambda mode. A micro-benchmark shows no performance
impact, either way. *)methodprivatelist_fold_left:'env'a.('env->'a->'s)->'env->'s->'alist->'s=funfenvsxs->matchxswith|[]->s|x::xs->lets=self#pluss(fenvx)inself#list_fold_leftfenvsxsmethodprivatevisit_nativeint:'env.'env->nativeint->'s=fun_env_->self#zeromethodprivatevisit_option:'env'a.('env->'a->'s)->'env->'aoption->'s=funfenvox->matchoxwith|Somex->fenvx|None->self#zeromethodprivatevisit_ref:'env'a.('env->'a->'s)->'env->'aref->'s=funfenvrx->fenv!rxmethodprivatevisit_result:'env'a'e.('env->'a->'s)->('env->'e->'s)->'env->('a,'e)result->'s=funfgenvr->matchrwith|Oka->fenva|Errorb->genvbmethodprivatevisit_string:'env.'env->string->'s=fun_env_->self#zeromethodprivatevisit_unit:'env.'env->unit->'s=fun_env_->self#zeroend(* -------------------------------------------------------------------------- *)(* [mapreduce] *)classvirtual['self]mapreduce=object(self:'self)inherit['s]monoidmethodprivatevisit_array:'env'a'b.('env->'a->'b*'s)->'env->'aarray->'barray*'s=funfenvxs->lets=refself#zeroinletxs=Array.map(funx->letx,sx=fenvxins:=self#plus!ssx;x)xsinxs,!smethodprivatevisit_bool:'env.'env->bool->bool*'s=fun_x->x,self#zeromethodprivatevisit_bytes:'env.'env->bytes->bytes*'s=fun_x->x,self#zeromethodprivatevisit_char:'env.'env->char->char*'s=fun_x->x,self#zeromethodprivatevisit_float:'env.'env->float->float*'s=fun_x->x,self#zeromethodprivatevisit_int:'env.'env->int->int*'s=fun_x->x,self#zeromethodprivatevisit_int32:'env.'env->int32->int32*'s=fun_x->x,self#zeromethodprivatevisit_int64:'env.'env->int64->int64*'s=fun_x->x,self#zeromethodprivatevisit_lazy_t:'env'a'b.('env->'a->'b*'s)->'env->'aLazy.t->'bLazy.t*'s=funfenv(lazyx)->(* Because we must compute a summary now, it seems that we have to
force the suspension now. One should be aware that this is not
the same behavior as the one we chose in the class [map]. *)lety,s=fenvxinlazyy,smethodprivatevisit_list:'env'a'b.('env->'a->'b*'s)->'env->'alist->'blist*'s=funfenvxs->matchxswith|[]->[],self#zero|x::xs->letx,sx=fenvxinletxs,sxs=self#visit_listfenvxsinx::xs,self#plussxsxs(* This is not the same strategy as in the class [reduce], where we
used an accumulator and a tail-recursive left fold. Here, we are
using a right fold. The order in which list elements are visited
is left-to-right in both cases, but the tree of [self#plus] ops
is not balanced the same way. *)methodprivatevisit_nativeint:'env.'env->nativeint->nativeint*'s=fun_x->x,self#zeromethodprivatevisit_option:'env'a_0'a_1.('env->'a_0->'a_1*'s)->'env->'a_0option->'a_1option*'s=funvisit_'aenvthis->matchthiswith|None->None,self#zero|Somec0->letr0,s0=visit_'aenvc0inSomer0,s0methodprivatevisit_ref:'env'a_0'a_1.('env->'a_0->'a_1*'s)->'env->'a_0ref->'a_1ref*'s=funvisit_'aenvthis->letr0,s0=visit_'aenv!thisinrefr0,s0methodprivatevisit_result:'env'a_0'a_1'b_0'b_1.('env->'a_0->'a_1*'s)->('env->'b_0->'b_1*'s)->'env->('a_0,'b_0)result->('a_1,'b_1)result*'s=funvisit_'avisit_'benvthis->matchthiswith|Okc0->letr0,s0=visit_'aenvc0inOkr0,s0|Errorc0->letr0,s0=visit_'benvc0inErrorr0,s0methodprivatevisit_string:'env.'env->string->string*'s=fun_x->x,self#zeromethodprivatevisit_unit:'env.'env->unit->unit*'s=fun_x->x,self#zeroend(* -------------------------------------------------------------------------- *)(* [fold] *)class['self]fold=object(_self)(* No methods are provided, as we do not wish to fix the types of these
methods. It is up to the user to inherit from a class that defines
appropriate methods. Note that [VisitorsRuntime.map] is likely to be
appropriate in many situations. *)end(* -------------------------------------------------------------------------- *)(* [iter2] *)class['self]iter2=object(self)methodprivatevisit_array:'env'a'b.('env->'a->'b->unit)->'env->'aarray->'barray->unit=funfenvxs1xs2->(* We inline [Array.iter2]. *)ifArray.lengthxs1=Array.lengthxs2thenfori=0toArray.lengthxs1-1dofenv(Array.unsafe_getxs1i)(Array.unsafe_getxs2i)doneelsefail()methodprivatevisit_bool:'env.'env->bool->bool->unit=fun_x1x2->ifx1=x2then()elsefail()methodprivatevisit_bytes:'env.'env->bytes->bytes->unit=fun_x1x2->ifx1=x2then()elsefail()methodprivatevisit_char:'env.'env->char->char->unit=fun_x1x2->ifx1=x2then()elsefail()methodprivatevisit_float:'env.'env->float->float->unit=fun_x1x2->ifx1=x2then()elsefail()methodprivatevisit_int:'env.'env->int->int->unit=fun_x1x2->ifx1=x2then()elsefail()methodprivatevisit_int32:'env.'env->int32->int32->unit=fun_x1x2->ifx1=x2then()elsefail()methodprivatevisit_int64:'env.'env->int64->int64->unit=fun_x1x2->ifx1=x2then()elsefail()methodprivatevisit_lazy_t:'env'a'b.('env->'a->'b->unit)->'env->'aLazy.t->'bLazy.t->unit=funfenv(lazyx1)(lazyx2)->fenvx1x2methodprivatevisit_list:'env'a'b.('env->'a->'b->unit)->'env->'alist->'blist->unit=funfenvxs1xs2->matchxs1,xs2with|[],[]->()|x1::xs1,x2::xs2->fenvx1x2;self#visit_listfenvxs1xs2|_,_->fail()methodprivatevisit_nativeint:'env.'env->nativeint->nativeint->unit=fun_x1x2->ifx1=x2then()elsefail()methodprivatevisit_option:'env'a'b.('env->'a->'b->unit)->'env->'aoption->'boption->unit=funfenvox1ox2->matchox1,ox2with|None,None->()|Somex1,Somex2->fenvx1x2|_,_->fail()methodprivatevisit_ref:'env'a'b.('env->'a->'b->unit)->'env->'aref->'bref->unit=funfenvrx1rx2->fenv!rx1!rx2methodprivatevisit_result:'env'a'b'e'f.('env->'a->'b->unit)->('env->'e->'f->unit)->'env->('a,'e)result->('b,'f)result->unit=funfgenvr1r2->matchr1,r2with|Oka1,Oka2->fenva1a2|Errorb1,Errorb2->genvb1b2|_,_->fail()methodprivatevisit_string:'env.'env->string->string->unit=fun_x1x2->ifx1=x2then()elsefail()methodprivatevisit_unit:'env.'env->unit->unit->unit=fun__x1_x2->()end(* -------------------------------------------------------------------------- *)(* [map2] *)class['self]map2=object(self)methodprivatevisit_array:'env'a'b'c.('env->'a->'b->'c)->'env->'aarray->'barray->'carray=funfenvxs1xs2->ifArray.lengthxs1=Array.lengthxs2thenArray.mapi(funix1->fenvx1xs2.(i))xs1(* Array.map2 (f env) xs1 xs2 *)(* We avoid [Array.map2] because it does not exist in OCaml 4.02. *)elsefail()methodprivatevisit_bool:'env.'env->bool->bool->bool=fun_x1x2->ifx1=x2thenx1elsefail()methodprivatevisit_bytes:'env.'env->bytes->bytes->bytes=fun_x1x2->ifx1=x2thenx1elsefail()methodprivatevisit_char:'env.'env->char->char->char=fun_x1x2->ifx1=x2thenx1elsefail()methodprivatevisit_float:'env.'env->float->float->float=fun_x1x2->ifx1=x2thenx1elsefail()methodprivatevisit_int:'env.'env->int->int->int=fun_x1x2->ifx1=x2thenx1elsefail()methodprivatevisit_int32:'env.'env->int32->int32->int32=fun_x1x2->ifx1=x2thenx1elsefail()methodprivatevisit_int64:'env.'env->int64->int64->int64=fun_x1x2->ifx1=x2thenx1elsefail()methodprivatevisit_lazy_t:'env'a'b'c.('env->'a->'b->'c)->'env->'aLazy.t->'bLazy.t->'cLazy.t=funfenvthx1thx2->(* As in [map]. *)lazy(fenv(Lazy.forcethx1)(Lazy.forcethx2))methodprivatevisit_list:'env'a'b'c.('env->'a->'b->'c)->'env->'alist->'blist->'clist=funfenvxs1xs2->matchxs1,xs2with|[],[]->[]|x1::xs1,x2::xs2->letx=fenvx1x2inx::self#visit_listfenvxs1xs2|_,_->fail()methodprivatevisit_nativeint:'env.'env->nativeint->nativeint->nativeint=fun_x1x2->ifx1=x2thenx1elsefail()methodprivatevisit_option:'env'a'b'c.('env->'a->'b->'c)->'env->'aoption->'boption->'coption=funfenvox1ox2->matchox1,ox2with|None,None->None|Somex1,Somex2->letx=fenvx1x2inSomex|_,_->fail()methodprivatevisit_ref:'env'a'b'c.('env->'a->'b->'c)->'env->'aref->'bref->'cref=funfenvrx1rx2->ref(fenv!rx1!rx2)methodprivatevisit_result:'env'a'b'c'e'f'g.('env->'a->'b->'c)->('env->'e->'f->'g)->'env->('a,'e)result->('b,'f)result->('c,'g)result=funfgenvr1r2->matchr1,r2with|Oka1,Oka2->Ok(fenva1a2)|Errorb1,Errorb2->Error(genvb1b2)|_,_->fail()methodprivatevisit_string:'env.'env->string->string->string=fun_x1x2->ifx1=x2thenx1elsefail()methodprivatevisit_unit:'env.'env->unit->unit->unit=fun__x1_x2->()end(* -------------------------------------------------------------------------- *)(* [reduce2] *)classvirtual['self]reduce2=object(self:'self)inherit['s]monoidmethodprivatevisit_array:'env'a'b.('env->'a->'b->'s)->'env->'aarray->'barray->'s=funfenvxs1xs2->(* OCaml does not offer [Array.fold_left2], so we use [Array.iter2],
which we inline. *)ifArray.lengthxs1=Array.lengthxs2thenlets=refself#zeroinfori=0toArray.lengthxs1-1doletx1=Array.unsafe_getxs1iandx2=Array.unsafe_getxs2iins:=self#plus!s(fenvx1x2)done;!selsefail()methodprivatevisit_bool:'env.'env->bool->bool->'s=fun_envx1x2->ifx1=x2thenself#zeroelsefail()methodprivatevisit_bytes:'env.'env->bytes->bytes->'s=fun_envx1x2->ifx1=x2thenself#zeroelsefail()methodprivatevisit_char:'env.'env->char->char->'s=fun_envx1x2->ifx1=x2thenself#zeroelsefail()methodprivatevisit_float:'env.'env->float->float->'s=fun_envx1x2->ifx1=x2thenself#zeroelsefail()methodprivatevisit_int:'env.'env->int->int->'s=fun_envx1x2->ifx1=x2thenself#zeroelsefail()methodprivatevisit_int32:'env.'env->int32->int32->'s=fun_envx1x2->ifx1=x2thenself#zeroelsefail()methodprivatevisit_int64:'env.'env->int64->int64->'s=fun_envx1x2->ifx1=x2thenself#zeroelsefail()methodprivatevisit_lazy_t:'env'a'b.('env->'a->'b->'s)->'env->'aLazy.t->'bLazy.t->'s=funfenv(lazyx1)(lazyx2)->fenvx1x2methodprivatevisit_list:'env'a'b.('env->'a->'b->'s)->'env->'alist->'blist->'s=funfenvxs1xs2->ifList.lengthxs1=List.lengthxs2thenList.fold_left2(funsx1x2->self#pluss(fenvx1x2))self#zeroxs1xs2elsefail()methodprivatevisit_nativeint:'env.'env->nativeint->nativeint->'s=fun_envx1x2->ifx1=x2thenself#zeroelsefail()methodprivatevisit_option:'env'a'b.('env->'a->'b->'s)->'env->'aoption->'boption->'s=funfenvox1ox2->matchox1,ox2with|Somex1,Somex2->fenvx1x2|None,None->self#zero|Some_,None|None,Some_->fail()methodprivatevisit_ref:'env'a'b.('env->'a->'b->'s)->'env->'aref->'bref->'s=funfenvrx1rx2->fenv!rx1!rx2methodprivatevisit_result:'env'a'b'e'f.('env->'a->'b->'s)->('env->'e->'f->'s)->'env->('a,'e)result->('b,'f)result->'s=funfgenvr1r2->matchr1,r2with|Oka1,Oka2->fenva1a2|Errorb1,Errorb2->genvb1b2|Ok_,Error_|Error_,Ok_->fail()methodprivatevisit_string:'env.'env->string->string->'s=fun_envx1x2->ifx1=x2thenself#zeroelsefail()methodprivatevisit_unit:'env.'env->unit->unit->'s=fun_env()()->self#zeroend(* -------------------------------------------------------------------------- *)(* [mapreduce2] *)classvirtual['self]mapreduce2=object(self)inherit['s]monoidmethodprivatevisit_array:'env'a'b'c.('env->'a->'b->'c*'s)->'env->'aarray->'barray->'carray*'s=funfenvxs1xs2->letn1=Array.lengthxs1andn2=Array.lengthxs2inifn1=n2thenlets=refself#zeroinletxs=Array.initn1(funi->letx1=Array.unsafe_getxs1iandx2=Array.unsafe_getxs2iinletx,sx=fenvx1x2ins:=self#plus!ssx;x)inxs,!selsefail()methodprivatevisit_bool:'env.'env->bool->bool->bool*'s=fun_x1x2->ifx1=x2thenx1,self#zeroelsefail()methodprivatevisit_bytes:'env.'env->bytes->bytes->bytes*'s=fun_x1x2->ifx1=x2thenx1,self#zeroelsefail()methodprivatevisit_char:'env.'env->char->char->char*'s=fun_x1x2->ifx1=x2thenx1,self#zeroelsefail()methodprivatevisit_float:'env.'env->float->float->float*'s=fun_x1x2->ifx1=x2thenx1,self#zeroelsefail()methodprivatevisit_int:'env.'env->int->int->int*'s=fun_x1x2->ifx1=x2thenx1,self#zeroelsefail()methodprivatevisit_int32:'env.'env->int32->int32->int32*'s=fun_x1x2->ifx1=x2thenx1,self#zeroelsefail()methodprivatevisit_int64:'env.'env->int64->int64->int64*'s=fun_x1x2->ifx1=x2thenx1,self#zeroelsefail()methodprivatevisit_lazy_t:'env'a'b'c.('env->'a->'b->'c*'s)->'env->'aLazy.t->'bLazy.t->'cLazy.t*'s=funfenv(lazyx1)(lazyx2)->(* As in [mapreduce]. *)lety,s=fenvx1x2inlazyy,smethodprivatevisit_list:'env'a_0'a_1'a_2.('env->'a_0->'a_1->'a_2*'s)->'env->'a_0list->'a_1list->'a_2list*'s=funvisit_'aenvthis_0this_1->matchthis_0,this_1with|[],[]->[],self#zero|c0_0::c1_0,c0_1::c1_1->letr0,s0=visit_'aenvc0_0c0_1inletr1,s1=self#visit_listvisit_'aenvc1_0c1_1inr0::r1,self#pluss0s1|_,_->fail()methodprivatevisit_nativeint:'env.'env->nativeint->nativeint->nativeint*'s=fun_x1x2->ifx1=x2thenx1,self#zeroelsefail()methodprivatevisit_option:'env'a_0'a_1'a_2.('env->'a_0->'a_1->'a_2*'s)->'env->'a_0option->'a_1option->'a_2option*'s=funvisit_'aenvthis_0this_1->matchthis_0,this_1with|None,None->None,self#zero|Somec0_0,Somec0_1->letr0,s0=visit_'aenvc0_0c0_1inSomer0,s0|_,_->fail()methodprivatevisit_ref:'env'a_0'a_1'a_2.('env->'a_0->'a_1->'a_2*'s)->'env->'a_0ref->'a_1ref->'a_2ref*'s=funvisit_'aenvthis_0this_1->letr0,s0=visit_'aenv!this_0!this_1inrefr0,s0methodprivatevisit_result:'env'a_0'a_1'a_2'b_0'b_1'b_2.('env->'a_0->'a_1->'a_2*'s)->('env->'b_0->'b_1->'b_2*'s)->'env->('a_0,'b_0)result->('a_1,'b_1)result->('a_2,'b_2)result*'s=funvisit_'avisit_'benvthis_0this_1->matchthis_0,this_1with|Okc0_0,Okc0_1->letr0,s0=visit_'aenvc0_0c0_1inOkr0,s0|Errorc0_0,Errorc0_1->letr0,s0=visit_'benvc0_0c0_1inErrorr0,s0|_,_->fail()methodprivatevisit_string:'env.'env->string->string->string*'s=fun_x1x2->ifx1=x2thenx1,self#zeroelsefail()methodprivatevisit_unit:'env.'env->unit->unit->unit*'s=fun_()()->(),self#zeroend(* -------------------------------------------------------------------------- *)(* [fold2] *)class['self]fold2=object(_self)(* See the comment in the class [fold] above. *)end