Library SSProve.Mon.MonadExamples

From Coq Require Import ssreflect List.
From SSProve.Mon Require Export Base.
From SSProve.Mon Require Import SPropBase SPropMonadicStructures Monoid.

Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Set Primitive Projections.
Set Universe Polymorphism.

(* The identity monad *)
Program Definition Identity : Monad :=
  @mkMonad (fun XX) (fun _ xx) (fun X Y x ff x) _ _ _.

(* The identity monad has a monad morphism to any other monad *)
Section IdentityInitial.
  Context (M:Monad).

  Program Definition ret_mmorph : MonadMorphism Identity M :=
    @mkMorphism _ _ (@ret M) _ _.
  Next Obligation. rewrite /bind monad_law1 //. Qed.
  (* We just prove the existence, not the unicity... *)

End IdentityInitial.

Section State.
  Context (S: Type).

  Program Definition St : Monad :=
    @mkMonad (fun XS X × S) (fun A a sa, s)
             (fun A B m f slet ms := m s in f (nfst ms) (nsnd ms))
             _ _ _.
  Definition get : St S := fun ss, s.
  Definition put (s:S) : St unit := fun s0tt, s.
End State.

Section Update.
  Context (M:monoid) (X:monoid_action M).

  Definition UpdFromLaws pf1 pf2 pf3 : Monad :=
    @mkMonad (fun AX A × M) (fun A a xa, e M)
             (fun A B m f xlet mx := m x in
                            let fx := f (nfst mx) (nsnd mx x) in
                            nfst fx, nsnd fx nsnd mx) pf1 pf2 pf3.
  Import FunctionalExtensionality.
  Program Definition Upd : Monad :=
    UpdFromLaws _ _ _.
  Next Obligation.
    extensionality x ; rewrite monact_unit monoid_law2 //.
  Qed.
  Next Obligation.
    extensionality x; rewrite monoid_law1 //.
  Qed.
  Next Obligation.
    extensionality x. rewrite - !monact_mult !monoid_law3 //.
  Qed.
End Update.

Section FreeMonad.

  (* A signature where S is the type of operations and P describes the
     arity of each operations *)

  Context (S : Type) (P : S Type).

  Inductive FreeF A : Type :=
  | retFree : A FreeF A
  | opr : s, (P s FreeF A) FreeF A.

  Arguments opr [A] _ _.

  Fixpoint bindFree A B (c : FreeF A) (f : A FreeF B) : FreeF B :=
    match c with
    | retFree af a
    | opr s kopr s (fun pbindFree (k p) f)
    end.

  Import FunctionalExtensionality.
  Program Definition Free : Monad :=
    @mkMonad FreeF retFree bindFree _ _ _.
  Next Obligation.
    elim c ⇒ //= ? ? IH ; f_equal ; extensionality p ; apply IH.
  Qed.
  Next Obligation.
    elim c ⇒ //= ? ? IH ; f_equal ; extensionality p ; apply IH.
  Qed.

  Definition op (s : S) : Free (P s) :=
    opr s (@retFree _).

  Definition trace := list { s : S & P s }.

  Program Definition from_free (M:Monad) (f: s, M (P s))
    : MonadMorphism Free M :=
    @mkMorphism _ _
                (fix from_free A (m:Free A) {struct m} :=
                  match m return M A with
                  | retFree aret a
                  | opr s kbind (f s) (fun xfrom_free A (k x))
                  end
               ) _ _.
  Next Obligation.
    induction m⇒ //=.
    rewrite /bind monad_law1 //.
    rewrite /bind monad_law3.
    f_equal. extensionality a. apply H.
  Qed.
End FreeMonad.

Section Partiality.
  Inductive DivS := Omega.
  Definition DivAr : DivS Type := fun 'OmegaFalse.

  Definition Div := @Free DivS DivAr.
  Definition Ω : Div False := op _ Omega.
End Partiality.

Section Exceptions.
  Context (E:Type).

  Inductive ExnS := Raise of E.
  Definition ExnAr : ExnS Type := fun '(Raise _) ⇒ False.

  Definition Exn := @Free ExnS ExnAr.
  Definition raise : E Exn False := fun eop _ (Raise e).
  Definition catch {A} (m : Exn A) (merr : E Exn A) : Exn A :=
    match m with
    | retFree am
    | @opr _ _ _ (Raise e) _merr e
    end.
End Exceptions.

Section NonDeterminismSet.
  Import SPropNotations FunctionalExtensionality SPropAxioms.

  Program Definition NDSet : Monad :=
    @mkMonad (fun XX Prop)
             (fun X xfun x'x = x')
             (fun X Y c ffun y x, c x f x y) _ _ _.
  Next Obligation.
    extensionality y; apply sprop_ext; do 2 split.
    + intros [x [eq H]]; induction eq⇒ //.
    + intro; a; intuition.
  Qed.
  Next Obligation.
    extensionality y; apply sprop_ext; do 2 split.
    + intros [x [H eq]]. induction eq⇒ //.
    + intro. y. intuition.
  Qed.
  Next Obligation.
    extensionality y; apply sprop_ext; do 2 split.
    + intros [b [[a [H1 H2]] H3]].
      eexists ; split ; [|eexists;split]; eassumption.
    + intros [a [H1 [b [H2 H3]]]].
      eexists ; split ; [eexists;split|]; eassumption.
  Qed.

  Definition pick_set : NDSet bool := fun bTrue.
End NonDeterminismSet.

Section NonDeterminismList.

  Lemma concat_map_nil : A (l : list A),
    concat (List.map (fun xx :: nil) l) = l.
  Proof.
    induction l.
    - reflexivity.
    - simpl. rewrite IHl. reflexivity.
  Qed.

  Program Definition ListM : Monad :=
    @mkMonad (fun Alist A)
             (fun A aa :: nil)
             (fun A B m fconcat (List.map f m)) _ _ _.
  Next Obligation. apply app_nil_r. Qed.
  Next Obligation. apply concat_map_nil. Qed.
  Next Obligation.
    induction c⇒ //=.
    rewrite map_app concat_app IHc //.
  Qed.

  Definition choose {A} (l : list A) : ListM A := l.
  Definition pick : ListM bool := true :: false :: nil.

End NonDeterminismList.

Section IO.
  Context (Inp Oup : Type).

  Inductive IOS : Type := Read : IOS | Write : Oup IOS.
  Definition IOAr (op : IOS) : Type :=
    match op with
    | ReadInp
    | Write _unit
    end.

  Definition IO := @Free IOS IOAr.

  Definition read : IO Inp := op _ Read.
  Definition write (o:Oup) : IO unit := op _ (Write o).
End IO.