include "utilities/extralib.ma". include "common/Errors.ma". (* IO monad *) inductive IO (output:Type[0]) (input:output → Type[0]) (T:Type[0]) : Type[0] ≝ | Interact : ∀o:output. (input o → IO output input T) → IO output input T | Value : T → IO output input T | Wrong : errmsg → IO output input T. include "utilities/proper.ma". (* a weak form of extensionality *) axiom interact_proper : ∀O,I,T,o.∀f,g : I o → IO O I T.(∀i. f i = g i) → Interact … o f = Interact … o g. let rec bindIO (O:Type[0]) (I:O → Type[0]) (T,T':Type[0]) (v:IO O I T) (f:T → IO O I T') on v : IO O I T' ≝ match v with [ Interact out k ⇒ (Interact ??? out (λres. bindIO O I T T' (k res) f)) | Value v' ⇒ (f v') | Wrong m ⇒ Wrong O I T' m ]. include "utilities/monad.ma". definition IOMonad ≝ λO,I. MakeMonadProps (* the monad *) (IO O I) (* return *) (λX.Value … X) (* bind *) (bindIO O I) ???. / by / [(* bind_ret *) #X#m elim m normalize // #o#f#Hi @interact_proper // |(* bind_bind *) #X#Y#Z#m#f#g elim m normalize [2,3://] (* Interact *) #o#f #Hi @interact_proper // ] qed. definition bindIO2 ≝ λO,I. m_bind2 (IOMonad O I). include "hints_declaration.ma". unification hint 0 ≔ O, I, T; N ≟ IOMonad O I, M ≟ max_def N, M' ≟ m_def M (*******************************************) ⊢ IO O I T ≡ monad M' T . definition err_to_io : ∀O,I,T. res T → IO O I T ≝ λO,I,T,v. match v with [ OK v' ⇒ Value O I T v' | Error m ⇒ Wrong O I T m ]. coercion err_to_io : ∀O,I,A.∀c:res A.IO O I A ≝ err_to_io on _c:res ? to IO ???. definition err_to_io_sig : ∀O,I,T.∀P:T → Prop. res (Sig T P) → IO O I (Sig T P) ≝ λO,I,T,P,v. match v with [ OK v' ⇒ Value O I (Sig T P) v' | Error m ⇒ Wrong O I (Sig T P) m ]. (*coercion err_to_io_sig : ∀O,I,A.∀P:A → Prop.∀c:res (Sig A P).IO O I (Sig A P) ≝ err_to_io_sig on _c:res (Sig ??) to IO ?? (Sig ??).*) let rec P_io O I (A:Type[0]) (P:A → Prop) (v:IO O I A) on v : Prop ≝ match v return λ_.Prop with [ Wrong _ ⇒ True | Value z ⇒ P z | Interact out k ⇒ ∀v'.P_io O I A P (k v') ]. let rec P_io' O I (A:Type[0]) (P:A → Prop) (v:IO O I A) on v : Prop ≝ match v return λ_.Prop with [ Wrong _ ⇒ False | Value z ⇒ P z | Interact out k ⇒ ∀v'.P_io' O I A P (k v') ]. definition P_to_P_option_io : ∀O,I,A.∀P:A → Prop.option (IO O I A) → Prop ≝ λO,I,A,P,a.match a with [ None ⇒ False | Some y ⇒ P_io O I A P y ]. let rec io_inject_0 O I (A:Type[0]) (P:A → Prop) (a:IO O I A) (p:P_io O I A P a) on a : IO O I (Sig A P) ≝ (match a return λa'.P_io O I A P a' → ? with [ Wrong m ⇒ λ_. Wrong O I ? m | Value c ⇒ λp'. Value ??? (mk_Sig A P c p') | Interact out k ⇒ λp'. Interact ??? out (λv. io_inject_0 O I A P (k v) (p' v)) ]) p. definition io_inject : ∀O,I,A.∀P:A → Prop.∀a:option (IO O I A).∀p:P_to_P_option_io O I A P a.IO O I (Sig A P) ≝ λO,I,A.λP:A → Prop.λa:option (IO O I A).λp:P_to_P_option_io O I A P a. (match a return λa'.P_to_P_option_io O I A P a' → IO O I (Sig A P) with [ None ⇒ λp'.? | Some b ⇒ λp'. io_inject_0 O I A P b p' ]) p. elim p'; qed. let rec io_eject O I (A:Type[0]) (P: A → Prop) (a:IO O I (Sig A P)) on a : IO O I A ≝ match a with [ Wrong m ⇒ Wrong ??? m | Value b ⇒ match b with [ mk_Sig w p ⇒ Value ??? w] | Interact out k ⇒ Interact ??? out (λv. io_eject ?? A P (k v)) ]. coercion io_inject : ∀O,I,A.∀P:A → Prop.∀a.∀p:P_to_P_option_io O I ? P a.IO O I (Sig A P) ≝ io_inject on a:option (IO ???) to IO ?? (Sig ? ?). coercion io_eject : ∀O,I,A.∀P:A → Prop.∀c:IO O I (Sig A P).IO O I A ≝ io_eject on _c:IO ?? (Sig ? ?) to IO ???. definition opt_to_io : ∀O,I,T.errmsg → option T → IO O I T ≝ λO,I,T,m,v. match v with [ None ⇒ Wrong ?? T m | Some v' ⇒ Value ??? v' ]. lemma sig_bindIO_OK: ∀O,I,A,B. ∀P:A → Prop. ∀P':B → Prop. ∀e:IO O I (Sig A P). ∀f:Sig A P → IO O I B. (∀v:A. ∀p:P v. P_io O I ? P' (f (mk_Sig A P v p))) → P_io O I ? P' (bindIO O I (Sig A P) B e f). #O #I #A #B #P #P' #e #f elim e; [ #out #k #IH #IH' whd; #res @IH //; | #v0 elim v0; #v #Hv #IH whd; @IH | //; ] qed. lemma sig_bindIO2_OK: ∀O,I,A,B,C. ∀P:(A×B) → Prop. ∀P':C → Prop. ∀e:IO O I (Sig (A×B) P). ∀f: A → B → IO O I C. (∀vA:A.∀vB:B. ∀p:P 〈vA,vB〉. P_io O I ? P' (f vA vB)) → P_io O I ? P' (bindIO2 O I A B C e f). #I #O #A #B #C #P #P' #e #f elim e; [ #out #k #IH #IH' whd; #res @IH @IH' | #v0 elim v0; #v elim v; #vA #vB #Hv #IH @IH //; | //; ] qed. lemma opt_bindIO_OK: ∀O,I,A,B,m. ∀P:B → Prop. ∀e:option A. ∀f: A → IO O I B. (∀v:A. e = Some A v → P_io O I ? P (f v)) → P_io O I ? P (bindIO O I A B (opt_to_io ??? m e) f). #I #O #A #B #m #P #e elim e; //; #v #f #H @H //; qed. lemma opt_bindIO2_OK: ∀O,I,A,B,C,m. ∀P:C → Prop. ∀e:option (A×B). ∀f: A → B → IO O I C. (∀vA:A.∀vB:B. e = Some (A×B) 〈vA,vB〉 → P_io O I ? P (f vA vB)) → P_io O I ? P (bindIO2 O I A B C (opt_to_io ??? m e) f). #I #O #A #B #C #m #P #e elim e; //; #v cases v; #vA #vB #f #H @H //; qed. lemma res_bindIO_OK: ∀O,I,A,B. ∀P:B → Prop. ∀e:res A. ∀f: A → IO O I B. (∀v:A. e = OK A v → P_io O I ? P (f v)) → P_io O I ? P (bindIO O I A B e f). #I #O #A #B #P #e elim e; //; #v #f #H @H //; qed. lemma res_bindIO2_OK: ∀O,I,A,B,C. ∀P:C → Prop. ∀e:res (A×B). ∀f: A → B → IO O I C. (∀vA:A.∀vB:B. e = OK (A×B) 〈vA,vB〉 → P_io O I ? P (f vA vB)) → P_io O I ? P (bindIO2 O I A B C e f). #I #O #A #B #C #P #e elim e; //; #v cases v; #vA #vB #f #H @H //; qed. lemma bindIO_OK: ∀O,I,A,B. ∀P:B → Prop. ∀e:IO O I A. ∀f: A → IO O I B. (∀v:A. P_io O I ? P (f v)) → P_io O I ? P (bindIO O I A B e f). #I #O #A #B #P #e elim e; [ #out #k #IH #f #H whd; #res @IH //; | #v #f #H @H | //; ] qed. lemma bindIO2_OK: ∀O,I,A,B,C. ∀P:C → Prop. ∀e:IO O I (A×B). ∀f: A → B → IO O I C. (∀v1:A.∀v2:B. P_io O I ? P (f v1 v2)) → P_io O I ? P (bindIO2 O I A B C e f). #I #O #A #B #C #P #e elim e; [ #out #k #IH #f #H whd; #res @IH //; | #v cases v; #v1 #v2 #f #H @H | //; ] qed. lemma P_bindIO_OK: ∀O,I,A,B. ∀P':A → Prop. ∀P:B → Prop. ∀e:IO O I A. ∀f: A → IO O I B. P_io … P' e → (∀v:A. P' v → P_io O I ? P (f v)) → P_io O I ? P (bindIO O I A B e f). #I #O #A #B #P' #P #e elim e; [ #out #k #IH #f #He #H whd in He ⊢ %; #res @IH /2 by /; | #v #f #He #H @H @He | //; ] qed. lemma P_bindIO2_OK: ∀O,I,A,B,C. ∀P':A×B → Prop. ∀P:C → Prop. ∀e:IO O I (A×B). ∀f: A → B → IO O I C. P_io … P' e → (∀v1:A.∀v2:B. P' 〈v1,v2〉 → P_io O I ? P (f v1 v2)) → P_io O I ? P (bindIO2 O I A B C e f). #I #O #A #B #C #P' #P #e elim e; [ #out #k #IH #f #He #H whd in He ⊢ %; #res @IH /2 by /; | #v cases v; #v1 #v2 #f #He #H @H @He | //; ] qed. (* Is there a way to prove this without extensionality? *) (* lemma bind_assoc_r: ∀O,I,A,B,C,e,f,g. ∀ext:(∀T1,T2:Type[0].∀f,f':T1 → T2.(∀x.f x = f' x) → f = f'). bindIO O I B C (bindIO O I A B e f) g = bindIO O I A C e (λx.bindIO O I B C (f x) g). #O #I #A #B #C #e #f #g #ext elim e; [ #o #k #IH whd in ⊢ (??%%); @eq_f @ext @IH | #v @refl | #m @refl ] qed. *) definition bind_assoc_r ≝ λO,I.m_bind_bind (IOMonad O I). (* lemma extract_subset_pair_io: ∀O,I,A,B,C,P. ∀e:{e:A×B | P e}. ∀Q:A→B→IO O I C. ∀R:C→Prop. (∀a,b. eject ?? e = 〈a,b〉 → P 〈a,b〉 → P_io O I ? R (Q a b)) → P_io O I ? R (match eject ?? e with [ pair a b ⇒ Q a b ]). #I #O #A #B #C #P #e #Q #R cases e; #e' cases e'; normalize; [ *; | #e'' cases e''; #a #b #Pab #H normalize; /2 by _/; ] qed. *)