Theory GPV_Applicative

theory GPV_Applicative imports
  Generative_Probabilistic_Value
  SPMF_Applicative
begin

subsection ‹Applicative instance for @{typ "(_, 'out, 'in) gpv"}

definition ap_gpv :: "('a  'b, 'out, 'in) gpv  ('a, 'out, 'in) gpv  ('b, 'out, 'in) gpv"
where "ap_gpv f x = bind_gpv f (λf'. bind_gpv x (λx'. Done (f' x')))"

adhoc_overloading Applicative.ap ap_gpv

abbreviation (input) pure_gpv :: "'a  ('a, 'out, 'in) gpv"
where "pure_gpv  Done"

context includes applicative_syntax begin

lemma ap_gpv_id: "pure_gpv (λx. x)  x = x"
by(simp add: ap_gpv_def)

lemma ap_gpv_comp: "pure_gpv (∘)  u  v  w = u  (v  w)"
by(simp add: ap_gpv_def bind_gpv_assoc)

lemma ap_gpv_homo: "pure_gpv f  pure_gpv x = pure_gpv (f x)"
by(simp add: ap_gpv_def)

lemma ap_gpv_interchange: "u  pure_gpv x = pure_gpv (λf. f x)  u"
by(simp add: ap_gpv_def)

applicative gpv
for
  pure: pure_gpv
  ap: ap_gpv
by(rule ap_gpv_id ap_gpv_comp[unfolded o_def[abs_def]] ap_gpv_homo ap_gpv_interchange)+

lemma map_conv_ap_gpv: "map_gpv f (λx. x) gpv = pure_gpv f  gpv"
by(simp add: ap_gpv_def map_gpv_conv_bind)

lemma exec_gpv_ap:
  "exec_gpv callee (f  x) σ = 
   exec_gpv callee f σ  (λ(f', σ'). pure_spmf (λ(x', σ''). (f' x', σ''))  exec_gpv callee x σ')"
by(simp add: ap_gpv_def exec_gpv_bind ap_spmf_conv_bind split_def)

lemma exec_gpv_ap_pure [simp]:
  "exec_gpv callee (pure_gpv f  x) σ = pure_spmf (apfst f)  exec_gpv callee x σ"
by(simp add: exec_gpv_ap apfst_def map_prod_def)

end

end