123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322(******************************************************************************)(* *)(* Monolith *)(* *)(* François Pottier *)(* *)(* Copyright Inria. All rights reserved. This file is distributed under the *)(* terms of the GNU Lesser General Public License as published by the Free *)(* Software Foundation, either version 3 of the License, or (at your *)(* option) any later version, as described in the file LICENSE. *)(* *)(******************************************************************************)(* This module offers utility functions that can play a role in scenarios.
This means that we must make them available to the user. A simple-minded
approach would be to print their definitions as part of error scenarios.
It seems preferable to just make them available as part of the Monolith
API, so the user can type [#require "monolith";;] in the OCaml REPL and
will have access to all functions in [Monolith.Support]. *)(* We define [Sup] as a short name for [Monolith.Support] at the beginning
of every scenario. This is done in [Engine.main]. *)letsupportname=Code.constant("Sup."^name)(* -------------------------------------------------------------------------- *)moduleFun=structletidx=xmoduleId=structletappearance=support"Fun.id"(* The following is an optional optimization: when [id] is applied to at
least one argument, we can perform beta-reduction on the fly, so that
the application of [id] becomes invisible. *)letappearance=Code.custom(funactuals->matchactualswith|x::more->Print.applyxmore|_->Code.applyappearanceactuals)letcode=id,appearanceendletrot2fyx=fxymoduleRot2=structletappearance=support"Fun.rot2"(* The following is an optional optimization: when [rot2] is applied to at
least three actual arguments, we can perform beta-reduction on the fly,
so that the application of [rot2] becomes invisible. This is permitted,
even though the actual arguments are not necessarily values, because
[rot2] uses its arguments linearly and because we can assume that at
most of one the arguments raises an exception. It is definitely a bit
fragile. *)letappearance=Code.custom(funactuals->matchactualswith|f::y::x::more->(* Someone who is crazy about detail will note that since [f]
moves from argument position back to head position, it no
longer needs to be parenthesized; but we have no way of
removing parentheses. *)Print.applyf(x::y::more)|_->(* We have fewer than three actual arguments; revert to the normal
appearance. *)Code.applyappearanceactuals)letcode=rot2,appearanceendletrot3fzxy=fxyzmoduleRot3=structletappearance=support"Fun.rot3"letappearance=Code.custom(funactuals->matchactualswith|f::z::x::y::more->Print.applyf(x::y::z::more)|_->Code.applyappearanceactuals)letcode=rot3,appearanceendletcurryfxy=f(x,y)moduleCurry=structletappearance=support"Fun.curry"letappearance=Code.custom(funactuals->matchactualswith|f::x::y::more->Print.applyf(PPrint.OCaml.tuple[x;y]::more)|_->Code.applyappearanceactuals)letcode=curry,appearanceendletuncurryf(x,y)=fxymoduleUncurry=structletappearance=support"Fun.uncurry"letcode=uncurry,appearanceendend(* -------------------------------------------------------------------------- *)moduleList=struct(* Testing two lists for equality. *)letequaleqxsys=List.lengthxs=List.lengthys&&List.for_all2eqxsys(* [List.to_seq] appears in OCaml 4.07. *)letrecto_seqxs=fun()->matchxswith|[]->Seq.Nil|x::xs->Seq.Cons(x,to_seqxs)moduleToSeq=structletappearance=support"List.to_seq"letcode=to_seq,appearanceendend(* -------------------------------------------------------------------------- *)moduleExn=struct(* Catching all exceptions. *)lethandlefx=tryOk(fx)with|Engine.PleaseBackOff->raiseEngine.PleaseBackOff|e->ErroremoduleHandle=structletappearance=support"Exn.handle"letcode=handle,appearanceendend(* -------------------------------------------------------------------------- *)moduleSeq=structincludeSeq(* One-shot functions. *)exceptionForcedTwiceletoneshotf=letforced=reffalseinfunx->if!forcedthenraiseForcedTwice;forced:=true;fx(* Affine sequences. *)openSeqletrecaffinexs=oneshot(fun()->matchxs()with|Nil->Nil|Cons(x,xs)->Cons(x,affinexs))letto_optionxs=matchxs()with|Nil->None|Cons(x,xs)->Some(x,xs)(* The composition [affine . List.to_seq]. *)letreclist_to_affine_seq(xs:'alist):'at=oneshot(fun()->matchxswith|[]->Nil|x::xs->Cons(x,list_to_affine_seqxs))moduleListToAffineSeq=structletappearance=support"Seq.list_to_affine_seq"letcode=list_to_affine_seq,appearanceendend(* -------------------------------------------------------------------------- *)(* This is a variant of affine sequences where it is possible to test at
runtime whether a sequence is valid (i.e., can still be forced). *)moduleVSeq=structtype'at={force:unit->'anode;valid:unit->bool}and'anode=|Nil|Consof'a*'atletvalidxs=xs.valid()exceptionForcedTwiceletoneshotf=letforced=reffalseinletforcex=if!forcedthenraiseForcedTwice;forced:=true;fxandvalid()=not!forcedin{force;valid}letrecaffine(xs:'aSeq.t):'at=oneshot(fun()->matchxs()with|Seq.Nil->Nil|Seq.Cons(x,xs)->Cons(x,affinexs))letto_optionxs=matchxs.force()with|Nil->None|Cons(x,xs)->Some(x,xs)letrecforget(xs:'at):'aSeq.t=fun()->matchxs.force()with|Nil->Seq.Nil|Cons(x,xs)->Seq.Cons(x,forgetxs)end