(** * ITrees as sets of traces *)
(* begin hide *)
List.
paco.
Core.ITreeDefinition
Eq.Eq
Eq.UpToTaus
Eq.SimUpToTaus
Eq.Shallow.
Local Open Scope itree.
(* end hide *)
Inductive trace {E : Type -> Type} {R : Type} : Type :=
| TEnd : trace
| TRet : R -> trace
| TEventEnd : forall {X}, E X -> trace
| TEventResponse : forall {X}, E X -> X -> trace -> trace
.
(* Append two traces, ignoring the end of the first trace. *)
Fixpoint app_trace {E R S} (tr1 : @trace E R) (tr2 : @trace E S) : @trace E S :=
match tr1 with
| TEventResponse e x tr => TEventResponse e x (app_trace tr tr2)
| _ => tr2
end.
(* Get the value in the TRet at the end of the trace, if it exists. *)
Fixpoint trace_ret {E R} (tr : @trace E R) : option R :=
match tr with
| TRet r => (Some r)
| TEventResponse _ _ tr => trace_ret tr
| _ => None
end.
Inductive is_traceF {E : Type -> Type} {R : Type} :
itreeF E R (itree E R) -> @trace E R -> Prop :=
| TraceEmpty : forall t, is_traceF t TEnd
| TraceRet : forall r, is_traceF (RetF r) (TRet r)
| TraceTau : forall t tr,
is_traceF (observe t) tr ->
is_traceF (TauF t) tr
| TraceVisEnd : forall X (e : E X) k,
is_traceF (VisF e k) (TEventEnd e)
| TraceVisContinue : forall X (e : E X) (x : X) k tr,
is_traceF (observe (k x)) tr ->
is_traceF (VisF e k) (TEventResponse e x tr)
.
Definition is_trace {E : Type -> Type} {R : Type} (t : itree E R) :=
is_traceF (observe t).
(* t1 ⊑ t2 *)
Definition trace_incl {E : Type -> Type} {R : Type} :
itree E R -> itree E R -> Prop :=
fun t1 t2 =>
forall tr, is_trace t1 tr -> is_trace t2 tr.
(* t1 ≡ t2 *)
Definition trace_eq {E : Type -> Type} {R : Type} :
itree E R -> itree E R -> Prop :=
fun t1 t2 =>
trace_incl t1 t2 /\ trace_incl t2 t1.

Lemma trace_eq_eutt : forall {E R} (t1 t2 : itree E R),
trace_eq t1 t2 -> t1 ≈ t2.