{-# OPTIONS --type-in-type
#-}
open import NeilPrelude
open import Equational
module Monad (M : Set → Set)
(_>>='_ : {A B : Set} → M A → (A → M B) → M B)
(ret : {A : Set} → A → M A)
(1stLaw : {A B : Set} → {a : A} → {f : A → M B} → ret a >>=' f ≡ f a)
(2ndLaw : {A : Set} → {ma : M A} → Extensionality → ma >>=' ret ≡ ma)
(3rdLaw : {A B C : Set} → {f : A → M B} → {g : B → M C} → Extensionality
→ (ma : M A) → (ma >>=' f) >>=' g ≡ ma >>=' (λ b → f b >>=' g))
where
infixl 4 _>>=_ _>>_
_>>=_ : {A B : Set} → M A → (A → M B) → M B
_>>=_ = _>>='_
_=<<_ : {A B : Set} → (A → M B) → M A → M B
_=<<_ = flip _>>=_
return : {A : Set} → A → M A
return = ret
ap : {A B : Set} → M (A → B) → M A → M B
ap mf ma = mf >>= λ f → ma >>= return ∘ f
liftM : {A B : Set} → (A → B) → M A → M B
liftM f = ap (return f)
join : {A : Set} → M (M A) → M A
join ma = ma >>= id
_>>_ : {A B : Set} → M A → M B → M B
ma >> mb = ma >>= const mb
_<<_ : {A B : Set} → M B → M A → M B
_<<_ = flip _>>_
applicativeIdentLaw : {A : Set} → {fa : M A} → Extensionality → return id >>= (λ f → fa >>= return ∘ f) ≡ fa
applicativeIdentLaw ext = trans 1stLaw (2ndLaw ext)
applicativeCompLaw : {A B C : Set} → {fa : M A} → {fbc : M (B → C)} → {fab : M (A → B)} → Extensionality →
((ret _∘_ >>= (λ f → fbc >>= return ∘ f)) >>= (λ f → fab >>= return ∘ f)) >>= (λ g → fa >>= return ∘ g)
≡
fbc >>= (λ f → (fab >>= λ g → fa >>= λ a → return (g a)) >>= λ b → return (f b))
applicativeCompLaw {_} {_} {_} {fa} {fbc} {fab} ext =
((ret _∘_ >>= (λ f → fbc >>= return ∘ f)) >>= (λ f → fab >>= return ∘ f)) >>= (λ g → fa >>= return ∘ g)
≡⟨ 3rdLaw ext (ret _∘_ >>= λ f → fbc >>= return ∘ f) ⟩
(ret _∘_ >>= (λ f → fbc >>= return ∘ f)) >>= (λ b → (fab >>= return ∘ b) >>= (λ g → fa >>= return ∘ g))
≡⟨ cong (flip _>>=_ (λ b → fab >>= return ∘ b >>= (λ g → fa >>= return ∘ g))) 1stLaw ⟩
(fbc >>= return ∘ _∘_) >>= (λ b → (fab >>= return ∘ b) >>= (λ g → fa >>= return ∘ g))
≡⟨ 3rdLaw ext fbc ⟩
fbc >>= (λ f → return (_∘_ f) >>= (λ b → (fab >>= return ∘ b) >>= (λ g → fa >>= return ∘ g)))
≡⟨ cong (_>>=_ fbc) (ext (λ f →
return (_∘_ f) >>= (λ b → fab >>= return ∘ b >>= (λ g → fa >>= return ∘ g))
≡⟨ 1stLaw ⟩
fab >>= return ∘ (_∘_ f) >>= (λ g → fa >>= return ∘ g)
≡⟨ 3rdLaw ext fab ⟩
fab >>= (λ h → return (f ∘ h) >>= (λ g → fa >>= return ∘ g) )
≡⟨ cong (_>>=_ fab) (ext (λ h →
return (f ∘ h) >>= (λ g → fa >>= return ∘ g)
≡⟨ 1stLaw ⟩
fa >>= return ∘ f ∘ h
≡⟨ cong (_>>=_ fa) (ext (λ _ → sym 1stLaw) ) ⟩
fa >>= (λ g → return (h g) >>= return ∘ f)
≡⟨ sym (3rdLaw ext fa) ⟩
(fa >>= return ∘ h) >>= return ∘ f
QED
)) ⟩
fab >>= (λ h → (fa >>= return ∘ h) >>= return ∘ f)
≡⟨ sym (3rdLaw ext fab) ⟩
fab >>= (λ h → fa >>= return ∘ h) >>= return ∘ f
QED
)) ⟩
fbc >>= (λ f → (fab >>= (λ h → fa >>= return ∘ h)) >>= return ∘ f)
QED
applicativeHomoLaw : {A B : Set} → {f : A → B} → {a : A} → (return f >>= λ g → return a >>= λ b → return (g b)) ≡ return (f a)
applicativeHomoLaw = trans 1stLaw 1stLaw
applicativeInterLaw : {A B : Set} → {fab : M (A → B)} → {a : A} → Extensionality →
fab >>= (λ f → ret a >>= (λ b → ret (f b))) ≡ ret (applyTo a) >>= (λ f → fab >>= (λ b → ret (f b)))
applicativeInterLaw {_} {_} {fab} {a} ext = fab >>= (λ f → ret a >>= (λ g → ret (f g)))
≡⟨ cong (_>>=_ fab) (ext (λ _ → 1stLaw)) ⟩
fab >>= (λ g → ret (g a))
≡⟨ sym 1stLaw ⟩
ret (applyTo a) >>= (λ f → fab >>= (λ g → ret (f g)))
QED
import Applicative
open Applicative M liftM return ap refl applicativeIdentLaw applicativeCompLaw applicativeHomoLaw applicativeInterLaw public