diff options
Diffstat (limited to 'bootstrap')
| -rw-r--r-- | bootstrap/Monads.v | 605 |
1 files changed, 605 insertions, 0 deletions
diff --git a/bootstrap/Monads.v b/bootstrap/Monads.v new file mode 100644 index 0000000000..26583b0be5 --- /dev/null +++ b/bootstrap/Monads.v @@ -0,0 +1,605 @@ +(* -*- coq-prog-args: ("-emacs-U" "-impredicative-set") -*- *) + +(* arnaud: on ne doit pas en avoir besoin normalement. *) + +Reserved Notation "'do' M x ':=' e 'in' u" (at level 200, M at level 0, x ident, e at level 200, u at level 200). +(*Reserved Notation "'do' e ; u" (at level 200, e at level 200, u at level 200).*) + +(*** Unit ***) + +Extract Inductive unit => unit [ + "()" +]. +Notation "()" := tt. + +(*** Bool ***) +Extract Inductive bool => bool [ + "true" + "false" +]. + +(*** List ***) +Extract Inductive list => list [ + "[]" + "(::)" +]. + +(*** Prod ***) +Extract Inductive prod => "(*)" [ + "(,)" +]. + +(*** Sum ***) +Print sum. +Extract Inductive sum => "Util.union" [ + "Util.Inl" + "Util.Inr" +]. + +(*** Exceptions ***) + +Parameter Exception : Set. +Extract Inlined Constant Exception => exn. + +Parameter tactic_failure : Exception -> Exception. +Extract Inlined Constant tactic_failure => "(fun e -> Proof_errors.TacticFailure e)". + +(*** Monoids ***) + +Module Monoid. + +Record T (M:Set) := { + zero : M; + prod : M -> M -> M +}. + +End Monoid. + +(*** Monads and related interfaces ***) +(* spiwack: the interfaces are presented in a mixin style. + I haven't tested other presentation, it just felt + convenient when I started *) + +Record Monad (T:Set->Set) := { + ret : forall{A:Set}, A->T A; + bind : forall{A B:Set}, T A -> (A -> T B) -> T B; + ignore : forall{A:Set}, T A -> T unit; + seq : forall{A:Set}, T unit -> T A -> T A +}. + +Notation "'do' M x ':=' e 'in' u" := (bind _ M e (fun x => u)). + +Record State (S:Set) (T:Set->Set) := { + set : S -> T unit; + get : T S +}. + +(* spiwack: Environment and Writer are given distinct interfaces from + State (rather than state beeing the composition of these) because I + don't really know how to combine the three together. However, we + might want to be able to arrange things so that we can say "I have a + number of things I can get, and a number of things I can set, some + of which can be got, and the other being monoids, then I have a + monad". I have yet to find how to do that though.*) +Record Environment (E:Set) (T:Set->Set) := { current : T E }. + +Record Writer (M:Set) (T:Set->Set) := { + put : M -> T unit +}. + +Record Logic (T:Set -> Set) := { + (* [zero] is usually argument free, but Coq likes to explain errors, + hence error messages should be carried around. *) + zero : forall {A}, Exception -> T A; + plus : forall {A}, T A -> (Exception -> T A) -> T A; + (** [split x] runs [x] until it either fails with [zero e] or finds + a result [a]. In the former case it returns [Inr e], otherwise + it returns [Inl (a,y)] where [y] can be run to get more results + from [x]. It is a variant of prolog's cut. *) + split : forall {A}, T A -> T ((A * (Exception -> T A)) + Exception)%type +}. +(** Writing (+) for plus and (>>=) for bind, we shall require that + + x+(y+z) = (x+y)+z + + zero+x = x + + x+zero = x + + (x+y)>>=k = (x>>=k)+(y>>=k) *) +(* The [T] argument represents the "global" effect: it is not + backtracked when backtracking occurs at a [plus]. *) +(* spiwack: hence, [T] will not be instanciated with a state monad + representing the proofs, we will use a surrounding state transformer + to that effect. [T] is meant to be instantiated with [IO]. *) + + +Module Id. + + Definition M : Monad (fun A => A) := {| + ret := fun _ x => x; + bind := fun _ _ x k => k x; + ignore := fun _ x => (); + seq := fun _ x k => k + |}. + +End Id. + +Module IOBase. + + Parameter T : Set -> Set. + Extract Constant T "'a" => "unit -> 'a". + Parameter Ref : Set -> Set. + Extract Constant Ref "'a" => "'a Pervasives.ref". + + Parameter ret : forall (A:Set), A -> T A. + Extract Constant ret => "fun a () -> a". + Extraction Implicit ret [A]. + Parameter bind : forall A B, T A -> (A->T B) -> T B. + Extract Constant bind => "fun a k () -> k (a ()) ()". + Extraction Implicit bind [A B]. + Parameter ignore : forall A, T A -> T unit. + Extract Constant ignore => "fun a () -> ignore (a ())". + Extraction Implicit ignore [A]. + Parameter seq : forall A, T unit -> T A -> T A. + Extract Constant seq => "fun a k () -> a (); k ()". + Extraction Implicit seq [A]. + + Parameter ref : forall (A:Set), A -> T (Ref A). + Extract Constant ref => "fun a () -> Pervasives.ref a". + Extraction Implicit ref [A]. + Parameter set : forall A, Ref A -> A -> T unit. + Extract Constant set => "fun r a () -> Pervasives.(:=) r a". + Extraction Implicit set [A]. + Parameter get : forall A, Ref A -> T A. + Extract Constant get => "fun r () -> Pervasives.(!) r". + Extraction Implicit get [A]. + + Parameter raise : forall A, Exception -> T A. + Extract Constant raise => "fun e () -> raise (Proof_errors.Exception e)". + Extraction Implicit raise [A]. + Parameter catch : forall A, T A -> (Exception -> T A) -> T A. + Extract Constant catch => "fun s h () -> try s () with Proof_errors.Exception e -> h e ()". + Extraction Implicit catch [A]. + + Parameter Int : Set. + Extract Constant Int => int. + Parameter timeout: forall A, Int -> T A -> T A. + Extract Constant timeout => "fun n t () -> + let timeout_handler _ = Pervasives.raise (Proof_errors.Exception Proof_errors.Timeout) in + let psh = Sys.signal Sys.sigalrm (Sys.Signal_handle timeout_handler) in + Pervasives.ignore (Unix.alarm n); + let restore_timeout () = + Pervasives.ignore (Unix.alarm 0); + Sys.set_signal Sys.sigalrm psh + in + try + let res = t () in + restore_timeout (); + res + with + | e -> restore_timeout (); Pervasives.raise e + ". + Extraction Implicit timeout [A]. + +End IOBase. + +(* spiwack: IO is split in two modules to avoid moot dependencies and + useless extracted code. *) +Module IO. + + Record S (Ref:Set->Set) (T:Set->Set) : Set := { + ref : forall {A:Set}, A -> T (Ref A); + set : forall {A:Set}, Ref A -> A -> T unit; + get : forall {A:Set}, Ref A -> T A; + + raise : forall {A:Set}, Exception -> T A; + catch : forall {A:Set}, T A -> (Exception -> T A) -> T A; + timeout : forall {A:Set}, IOBase.Int -> T A -> T A + }. + + Definition T : Set -> Set := IOBase.T. + Definition Ref : Set -> Set := IOBase.Ref. + + Definition M : Monad T := {| + ret := IOBase.ret; + bind := IOBase.bind; + ignore := IOBase.ignore; + seq := IOBase.seq + |}. + + Definition IO : S Ref T := {| + ref := IOBase.ref; + set := IOBase.set; + get := IOBase.get; + + raise := IOBase.raise; + catch := IOBase.catch; + timeout := IOBase.timeout + |}. + +End IO. + +Module State. +(** State monad transformer, adapted from Haskell' StateT *) + +Section Common. + + Variables (S:Set) (T₀:Set->Set) (M:Monad T₀). + + Definition T (A:Set):= S -> T₀ (A*S)%type. + + Definition F : Monad T := {| + ret A x s := ret _ M (x,s); + bind A B x k s := + do M x := x s in + let '(x,s) := x in + k x s; + ignore A x s := + do M x := x s in + let '(_,s) := x in + ret _ M ((),s); + seq A x k s := + do M x := x s in + let '((),s) := x in + k s + |}. + + Definition State : State S T := {| + set := (fun (x s:S) => ret _ M ((),x)) : S -> T unit ; + get := fun (s:S) => ret _ M (s,s) + |}. + + Definition lift : forall {A}, T₀ A -> T A := fun _ x s => + do M x := x in + ret _ M (x,s) + . + + Definition run : forall {A}, T A -> S -> T₀ (A*S) := fun _ x => x. + + Variable (L:Logic T₀). + + + Definition Logic : Logic T := {| + zero A e := lift (zero _ L e); + plus A x y s := plus _ L (x s) (fun e => y e s); + split A x s := + do M x := split _ L (x s) in + match x return T₀ (((A*(Exception->T A))+Exception)*S) with + | inr e => ret _ M (inr e,s) + | inl ((a,s),y) => + let y e (_:S) := y e in + ret _ M (inl (a,y) , s) + end + |}. + +End Common. + +End State. + + +Module Environment. +(** An environment monad transformer, like Haskell's ReaderT *) + +Section Common. + + Variable (E:Set) (T₀:Set->Set) (M:Monad T₀). + + Definition T (A:Set) := E -> T₀ A. + + Definition F : Monad T := {| + ret A x e := ret _ M x; + bind A B x k e := + do M x := x e in + k x e; + ignore A x e := ignore _ M (x e); + seq A x k e := seq _ M (x e) (k e) + |}. + + Definition Environment : Environment E T := {| + current e := ret _ M e + |}. + + + Variable (L:Logic T₀). + + + Definition Logic : Logic T := {| + zero A e env := zero _ L e; + plus A x y env := plus _ L (x env) (fun e => y e env); + split A x env := + do M x := split _ L (x env) in + match x return T₀ ((A*(Exception->T A))+Exception) with + | inr e => ret _ M (inr e) + | inl (a,y) => + let y e (_:E) := y e in + ret _ M (inl (a,y)) + end + |}. + + + Definition lift {A:Set} (x:T₀ A) : T A := fun _ => x. + + Definition run {A:Set} (x:T A) (e:E) : T₀ A := x e. + +End Common. + +End Environment. + +Module Writer. +(** A "Writer" monad transformer, that is the canonical monad associated + to a monoid. Adaptated from Haskell's WriterT *) + +Section Common. + + Variables (C:Set) (m:Monoid.T C) (T₀:Set->Set) (M:Monad T₀). + + Definition T (A:Set) := T₀ (A*C)%type. + + Definition F : Monad T := {| + ret A x := ret _ M (x,Monoid.zero _ m); + bind A B x k := + do M x := x in + let '(x,c) := x in + do M y := k x in + let '(y,c') := y in + ret _ M (y,Monoid.prod _ m c c'); + ignore A x := + do M x := x in + let '(_,c) := x in + ret _ M ((),c); + seq A x k := + do M x := x in + let '((),c) := x in + do M y := k in + let '(y,c') := y in + ret _ M (y,Monoid.prod _ m c c') + |}. + + Definition Writer : Writer C T := {| + put := fun (x:C) => ret _ M ((),x) : T unit + |}. + + Definition lift {A} (x:T₀ A) : T A := + do M x := x in + ret _ M (x, Monoid.zero _ m) + . + + Definition run {A} (x:T A) : T₀ (A*C)%type := x. + + Variable (L:Logic T₀). + + Definition Logic : Logic T := {| + zero A e := lift (zero _ L e); + plus A x y := plus _ L x y; + split A x := + do M x := split _ L x in + match x return T ((A*(Exception -> T A)) + Exception) with + | inr e => ret _ M (inr e, Monoid.zero _ m) + | inl ((a,c),y) => + ret _ M (inl (a,y), c) + end + |}. + +End Common. + +End Writer. + + +Module Logic. + +(* Double-continuation backtracking monads are reasonable folklore for + "search" implementations (including Tac interactive prover's + tactics). Yet it's quite hard to wrap your head around these. I + recommand reading a few times the "Backtracking, Interleaving, and + Terminating Monad Transformers" paper by O. Kiselyov, C. Chen, + D. Fridman. The peculiar shape of the monadic type is reminiscent + of that of the continuation monad transformer. + + The paper also contains the rational for the [split] abstraction. + + An explanation of how to derive such a monad from mathematical + principles can be found in "Kan Extensions for Program + Optimisation" by Ralf Hinze. + + One way to think of the [Logic] functor is to imagine ['a + Logic(X).t] to represent list of ['a] with an exception at the + bottom (leaving the monad-transforming issues aside, as they don't + really work well with lists). Each of the element is a valid + result, sequentialising with a [f:'a -> 'b t] is done by applying + [f] to each element and then flatten the list, [plus] is + concatenation, and [split] is pattern-matching. *) +(* spiwack: I added the primitives from [IO] directly in the [Logic] + signature for convenience. It doesn't really make sense, strictly + speaking, as they are somewhat deconnected from the semantics of + [Logic], but without an appropriate language for composition (some + kind of mixins?) I would be going nowhere with a gazillion + functors. *) + +Section Common. + + Variables (T₀:Set->Set) (M:Monad T₀). + + Definition FK (R:Set) : Set := Exception -> R. + Definition SK (A R:Set) : Set := A -> FK R -> R. + Definition T (A:Set) : Set := forall (R:Set), SK A (T₀ R) -> FK (T₀ R) -> T₀ R. + (* spiwack: the implementation is an adaptation of the aforementionned + "Backtracking, Interleaving, and Terminating Monad Transformers" + paper *) + (* spiwack: [fk] stands for failure continuation, and [sk] for success + continuation. *) + + Definition F : Monad T := {| + ret A x R sk fk := sk x fk; + bind A B x k R sk fk := + x _ (fun a fk => k a _ sk fk) fk; + ignore A x R sk fk := + x _ (fun _ fk => sk () fk) fk; + seq A x k R sk fk := + x _ (fun _ fk => k _ sk fk) fk + |}. + + Definition lift {A} (x:T₀ A) : T A := fun _ sk fk => + do M x := x in + sk x fk + . + + Definition _zero {A:Set} (e:Exception) : T A := fun _ _ fk => fk e. + Definition _plus {A:Set} (x:T A) (y:Exception -> T A) : T A := fun _ sk fk => + x _ sk (fun e => y e _ sk fk) + . + + (* For [reflect] and [split] see the "Backtracking, Interleaving, + and Terminating Monad Transformers" paper *) + Definition reflect {A:Set} (x:(A*(Exception -> T A)) + Exception) : T A := + match x with + | inr e => _zero e + | inl (a,x) => _plus (ret _ F a) x + end + . + + Definition lower {A:Set} (x:T A) : T₀ ((A*(Exception -> T A)) + Exception) := + let fk e := ret _ M (inr e) in + let lift_fk fk e := do F y := lift (fk e) in reflect y in + let sk a fk := ret _ M (inl (a, lift_fk fk)) in + x _ sk fk + . + + Definition Logic : Logic T := {| + zero := @_zero; + plus := @_plus; + split A x := lift (lower x) + |}. + + Variable (Ref:Set->Set) (IO:IO.S Ref T₀). + + Definition run {A:Set} (x:T A) : T₀ A := + let sk (a:A) _ : T₀ A := ret _ M a in + let fk e : T₀ A := IO.raise _ _ IO (tactic_failure e) in + x _ sk fk + . + +End Common. + +End Logic. + + +(*** Extraction **) + +Parameters (constr types evar_map goal env seffs:Set). +Extract Inlined Constant constr => "Term.constr". +Extract Inlined Constant types => "Term.types". +Extract Inlined Constant evar_map => "Evd.evar_map". +Extract Inlined Constant goal => "Goal.goal". +Extract Inlined Constant env => "Environ.env". + +Record proofview := { + initial : list (constr*types); + solution : evar_map; + comb : list goal +}. + +Definition LogicalState := proofview. +Definition LogicalMessageType := bool. +Definition LogicalEnvironment := env. +Definition LogicalMessage : Monoid.T LogicalMessageType := {| + Monoid.zero := true; + Monoid.prod x y := andb x y +|}. + +Definition NonLogicalType := IO.T. +Definition NonLogicalMonad : Monad NonLogicalType := IO.M. +Definition NonLogicalIO : IO.S IO.Ref NonLogicalType := IO.IO. + +Definition LogicalType := Eval compute in State.T LogicalState (Environment.T LogicalEnvironment (Writer.T LogicalMessageType (Logic.T NonLogicalType))). +Definition LogicalMonadBase := Logic.F NonLogicalType. +Definition LogicalMonadWriter := Writer.F _ LogicalMessage _ LogicalMonadBase. +Definition LogicalMonadEnv := Environment.F LogicalEnvironment _ LogicalMonadWriter. +Definition LogicalMonad : Monad LogicalType := State.F LogicalState _ LogicalMonadEnv. +Definition LogicalStateM : State LogicalState LogicalType := State.State LogicalState _ LogicalMonadEnv. +Definition LogicalReader : Environment LogicalEnvironment _ := Environment.Environment LogicalEnvironment _ LogicalMonadWriter. +Definition LogicalWriter : Writer LogicalMessageType _ := Writer.Writer LogicalMessageType _ (Logic.F NonLogicalType). +Definition LogicalLogic : Logic LogicalType := State.Logic _ _ LogicalMonadEnv (Environment.Logic _ _ LogicalMonadWriter (Writer.Logic _ LogicalMessage _ LogicalMonadBase (Logic.Logic _ NonLogicalMonad))). + +Module NonLogical. + + Definition t (a:Set) := Eval compute in NonLogicalType a. + Definition ref (a:Set) := Eval compute in IO.Ref a. + + Definition ret {a:Set} (x:a) : t a := Eval compute in ret _ NonLogicalMonad x. + Extraction Implicit ret [a]. + Definition bind {a b:Set} (x:t a) (k:a-> t b) : t b := Eval compute in bind _ NonLogicalMonad x k. + Extraction Implicit bind [a b]. + + Definition ignore {a:Set} (x:t a) : t unit := Eval compute in ignore _ NonLogicalMonad x. + Extraction Implicit ignore [a]. + Definition seq {a:Set} (x:t unit) (k:t a) : t a := Eval compute in seq _ NonLogicalMonad x k. + Extraction Implicit seq [a]. + + Definition new_ref {a:Set} (x:a) : t (ref a) := Eval compute in IO.ref _ _ NonLogicalIO x. + Extraction Implicit new_ref [a]. + Definition set {a:Set} (r:ref a) (x:a) : t unit := Eval compute in IO.set _ _ NonLogicalIO r x. + Extraction Implicit set [a]. + Definition get {a:Set} (r:ref a) : t a := Eval compute in IO.get _ _ NonLogicalIO r. + Extraction Implicit get [a]. + + Definition raise {a:Set} (e:Exception) : t a := Eval compute in IO.raise _ _ NonLogicalIO e. + Extraction Implicit raise [a]. + Definition catch {a:Set} (s:t a) (h:Exception -> t a) : t a := Eval compute in IO.catch _ _ NonLogicalIO s h. + Extraction Implicit catch [a]. + Definition timeout {a:Set} n (x:t a) : t a := Eval compute in IO.timeout _ _ NonLogicalIO n x. + Extraction Implicit timeout [a]. + + (* /!\ The extracted code for [run] performs effects. /!\ *) + Parameter run : forall a:Set, t a -> a. + Extract Constant run => "fun x -> try x () with Proof_errors.Exception e -> Pervasives.raise e". + Extraction Implicit run [a]. + +End NonLogical. + +Module Logical. + + Definition t (a:Set) := Eval compute in LogicalType a. + + Definition ret {a:Set} (x:a) : t a := Eval compute in ret _ LogicalMonad x. + Extraction Implicit ret [a]. + Definition bind {a b:Set} (x:t a) (k:a-> t b) : t b := Eval compute in bind _ LogicalMonad x k. + Extraction Implicit bind [a b]. + Definition ignore {a:Set} (x:t a) : t unit := Eval compute in ignore _ LogicalMonad x. + Extraction Implicit ignore [a]. + Definition seq {a:Set} (x:t unit) (k:t a) : t a := Eval compute in seq _ LogicalMonad x k. + Extraction Implicit seq [a]. + + Definition set (s:LogicalState) : t unit := Eval compute in set _ _ LogicalStateM s. + Definition get : t LogicalState := Eval compute in get _ _ LogicalStateM. + Print Environment.lift. + Definition put (m:LogicalMessageType) : t unit := Eval compute in State.lift _ _ LogicalMonadEnv (Environment.lift _ _ (put _ _ LogicalWriter m)). + Definition current : t LogicalEnvironment := Eval compute in State.lift _ _ LogicalMonadEnv (current _ _ LogicalReader). + + Definition zero {a:Set} (e:Exception) : t a := Eval compute in zero _ LogicalLogic e. + Extraction Implicit zero [a]. + Definition plus {a:Set} (x:t a) (y:Exception -> t a) : t a := Eval compute in plus _ LogicalLogic x y. + Extraction Implicit plus [a]. + Definition split {a:Set} (x:t a) : t ((a*(Exception -> t a))+Exception) := Eval compute in split _ LogicalLogic x. + Extraction Implicit split [a]. + Definition lift {a:Set} (x:NonLogical.t a) : t a := Eval compute in + State.lift _ _ LogicalMonadEnv (Environment.lift _ _ (Writer.lift _ LogicalMessage _ LogicalMonadBase (Logic.lift _ NonLogicalMonad x))). + Extraction Implicit lift [a]. + + Definition run {a:Set} (x:t a) (e:LogicalEnvironment) (s:LogicalState) : NonLogical.t ((a*LogicalState)*LogicalMessageType) := Eval compute in + Logic.run _ NonLogicalMonad _ NonLogicalIO (Writer.run _ _ (Environment.run _ _ (State.run _ _ x s) e)) + . + Extraction Implicit run [a]. + +End Logical. + + +Set Extraction Conservative Types. +Set Extraction File Comment " +This file has been generated by extraction of bootstrap/Monad.v. +It shouldn't be modified directly. To regenerate it run +coqtop -batch -impredicative-set bootstrap/Monad.v in Coq's source +directory. +". + +Extraction "proofs/proofview_gen.ml" NonLogical Logical. |
