rushby-noninterference/experimental/Mealy.v

100 lines
3.4 KiB
Coq
Raw Permalink Normal View History

2018-02-14 17:33:01 +01:00
From stdpp Require Import base.
2018-02-14 12:55:20 +01:00
Require Import Monoids.
Class Mealy (state action out : Type) := {
initial : state;
step : state -> action -> state;
output : state -> action -> out
}.
(** ** Auxiliary functions
We define a [run] of a machine [M], which is an extension of
the [step] function to lists of actions. We use a shortcut
[do_actions] for running the machine from the [initial] state. *)
Fixpoint run `{Mealy state action out} (s : state) (ls : list action) : state :=
match ls with
| nil => s
| a::tl => run (step s a) tl
end.
Definition do_actions `{Mealy state action out} : list action -> state := run initial.
(** The [test] function runs the required list of actions and examines the output of the resulting state on a specified action. *)
Definition test `{Mealy state action out} (ls : list action) : action -> out := output (do_actions ls).
Global Instance MealyMRet `{Monoid out op e} : MRet (λ A, (A * out)%type) :=
fun A x => (x, e).
Global Instance MealyMBind `{Monoid out op e} : MBind (λ A, (A * out)%type) :=
fun A B (f : A B * out) (x : A * out) =>
match x with
(x,x) => match f x with
(y,y) => (y, op x y)
end
end.
Global Instance MealyMonad `{Monoid out op e} `{Mealy state action out} :
Monad (λ A, (A * out)%type).
Proof. split; intros;
unfold mret, mbind; unfold MealyMRet, MealyMBind.
destruct m. rewrite right_id; auto.
apply H. (* TODO: why is this not being picked up automatically? *)
destruct (f x). rewrite left_id; auto. apply H.
destruct m. destruct (f a). destruct (g b).
rewrite associative. reflexivity. apply H.
Qed.
About run.
Class MSync (state action out : Type)
:= {
msync_mealy : Mealy state action out;
delayed : action -> (state -> Prop);
delayed_dec :> forall a s, Decision (delayed a s)
}.
Global Instance MSync_as_Mealy `{MS: MSync state action out}
: Mealy state action (option out) :=
{ initial := @initial _ _ _ msync_mealy
; step := fun s a => if (decide (delayed a s))
then s
else @step _ _ _ msync_mealy s a
; output := fun s a => if (decide (delayed a s))
then None
else Some (@output _ _ _ msync_mealy s a)
}.
Class MApi (domain : Type) (API : Type) (state action out : Type) :=
{ mapi_mealy : Mealy state action out
; domain_dec :> forall (x y : domain), Decision (x = y)
; dom_api : API -> domain
; sem_api : API -> list action
}.
Definition upd `{MApi domain API s a o}
(f : domain -> list a) a b :=
fun d => if (decide (a = d)) then b else f d.
Global Instance MApi_as_Mealy `{MA: MApi domain API state action out}
: Mealy (state * (domain -> list action)) API (option out)
:=
{ initial := (@initial _ _ _ mapi_mealy, (λ _,[]))
; step := fun s a => let (s', f) := s
in let step' := @step _ _ _ mapi_mealy
in match (f (dom_api a)) with
| [] => (s', upd f (dom_api a) (sem_api a))
| (x::xs) => (step' s' x, upd f (dom_api a) xs)
end
; output := fun s a => let (s', f) := s
in let output' := @output _ _ _ mapi_mealy
in match (f (dom_api a)) with
| [] => None
| (x::xs) => Some (output' s' x)
end
}.