{-# OPTIONS --cubical-compatible --safe #-}
module Data.List.Effectful where
open import Data.Bool.Base using (false; true)
open import Data.List.Base
using (List; map; [_]; ap; []; _∷_; _++_; concat; concatMap)
open import Data.List.Properties
using (++-identityʳ; ++-assoc; map-cong; concatMap-cong; map-concatMap;
concatMap-pure)
open import Effect.Choice using (RawChoice)
open import Effect.Empty using (RawEmpty)
open import Effect.Functor using (RawFunctor)
open import Effect.Applicative
using (RawApplicative; RawApplicativeZero; RawAlternative)
open import Effect.Monad
using (RawMonad; module Join; RawMonadZero; RawMonadPlus)
open import Function.Base using (flip; _∘_; const; _$_; id; _∘′_; _$′_)
open import Level using (Level)
open import Relation.Binary.PropositionalEquality.Core as ≡
using (_≡_; _≢_; _≗_; refl)
open import Relation.Binary.PropositionalEquality.Properties as ≡
open ≡.≡-Reasoning
private
variable
ℓ : Level
A : Set ℓ
functor : RawFunctor {ℓ} List
functor = record { _<$>_ = map }
applicative : RawApplicative {ℓ} List
applicative = record
{ rawFunctor = functor
; pure = [_]
; _<*>_ = ap
}
empty : RawEmpty {ℓ} List
empty = record { empty = [] }
choice : RawChoice {ℓ} List
choice = record { _<|>_ = _++_ }
applicativeZero : RawApplicativeZero {ℓ} List
applicativeZero = record
{ rawApplicative = applicative
; rawEmpty = empty
}
alternative : RawAlternative {ℓ} List
alternative = record
{ rawApplicativeZero = applicativeZero
; rawChoice = choice
}
monad : ∀ {ℓ} → RawMonad {ℓ} List
monad = record
{ rawApplicative = applicative
; _>>=_ = flip concatMap
}
join : List (List A) → List A
join = Join.join monad
monadZero : ∀ {ℓ} → RawMonadZero {ℓ} List
monadZero = record
{ rawMonad = monad
; rawEmpty = empty
}
monadPlus : ∀ {ℓ} → RawMonadPlus {ℓ} List
monadPlus = record
{ rawMonadZero = monadZero
; rawChoice = choice
}
module TraversableA {f g F} (App : RawApplicative {f} {g} F) where
open RawApplicative App
sequenceA : ∀ {A} → List (F A) → F (List A)
sequenceA [] = pure []
sequenceA (x ∷ xs) = _∷_ <$> x <*> sequenceA xs
mapA : ∀ {a} {A : Set a} {B} → (A → F B) → List A → F (List B)
mapA f = sequenceA ∘ map f
forA : ∀ {a} {A : Set a} {B} → List A → (A → F B) → F (List B)
forA = flip mapA
module TraversableM {m n M} (Mon : RawMonad {m} {n} M) where
open RawMonad Mon
open TraversableA rawApplicative public
renaming
( sequenceA to sequenceM
; mapA to mapM
; forA to forM
)
private
open module LMP {ℓ} = RawMonadPlus (monadPlus {ℓ = ℓ})
module MonadProperties where
left-identity : ∀ {ℓ} {A B : Set ℓ} (x : A) (f : A → List B) →
(pure x >>= f) ≡ f x
left-identity x f = ++-identityʳ (f x)
right-identity : ∀ {ℓ} {A : Set ℓ} (xs : List A) →
(xs >>= pure) ≡ xs
right-identity [] = refl
right-identity (x ∷ xs) = ≡.cong (x ∷_) (right-identity xs)
left-zero : ∀ {ℓ} {A B : Set ℓ} (f : A → List B) → (∅ >>= f) ≡ ∅
left-zero f = refl
right-zero : ∀ {ℓ} {A B : Set ℓ} (xs : List A) →
(xs >>= const ∅) ≡ ∅ {A = B}
right-zero [] = refl
right-zero (x ∷ xs) = right-zero xs
private
not-left-distributive :
let xs = true ∷ false ∷ []; f = pure; g = pure in
(xs >>= λ x → f x ∣ g x) ≢ ((xs >>= f) ∣ (xs >>= g))
not-left-distributive ()
right-distributive : ∀ {ℓ} {A B : Set ℓ}
(xs ys : List A) (f : A → List B) →
(xs ∣ ys >>= f) ≡ ((xs >>= f) ∣ (ys >>= f))
right-distributive [] ys f = refl
right-distributive (x ∷ xs) ys f = begin
f x ∣ (xs ∣ ys >>= f) ≡⟨ ≡.cong (f x ∣_) $ right-distributive xs ys f ⟩
f x ∣ ((xs >>= f) ∣ (ys >>= f)) ≡⟨ ≡.sym $ ++-assoc (f x) _ _ ⟩
((f x ∣ (xs >>= f)) ∣ (ys >>= f)) ∎
associative : ∀ {ℓ} {A B C : Set ℓ}
(xs : List A) (f : A → List B) (g : B → List C) →
(xs >>= λ x → f x >>= g) ≡ (xs >>= f >>= g)
associative [] f g = refl
associative (x ∷ xs) f g = begin
(f x >>= g) ∣ (xs >>= λ x → f x >>= g) ≡⟨ ≡.cong ((f x >>= g) ∣_) $ associative xs f g ⟩
(f x >>= g) ∣ (xs >>= f >>= g) ≡⟨ ≡.sym $ right-distributive (f x) (xs >>= f) g ⟩
(f x ∣ (xs >>= f) >>= g) ∎
cong : ∀ {ℓ} {A B : Set ℓ} {xs₁ xs₂} {f₁ f₂ : A → List B} →
xs₁ ≡ xs₂ → f₁ ≗ f₂ → (xs₁ >>= f₁) ≡ (xs₂ >>= f₂)
cong {xs₁ = xs} refl f₁≗f₂ = ≡.cong concat (map-cong f₁≗f₂ xs)
module Applicative where
private
module MP = MonadProperties
pam : ∀ {ℓ} {A B : Set ℓ} → List A → (A → B) → List B
pam xs f = xs >>= pure ∘ f
left-zero : ∀ {ℓ} {A B : Set ℓ} → (xs : List A) → (∅ ⊛ xs) ≡ ∅ {A = B}
left-zero xs = begin
∅ ⊛ xs ≡⟨⟩
(∅ >>= pam xs) ≡⟨ MonadProperties.left-zero (pam xs) ⟩
∅ ∎
right-zero : ∀ {ℓ} {A B : Set ℓ} → (fs : List (A → B)) → (fs ⊛ ∅) ≡ ∅
right-zero {ℓ} fs = begin
fs ⊛ ∅ ≡⟨⟩
(fs >>= pam ∅) ≡⟨ (MP.cong (refl {x = fs}) λ f →
MP.left-zero (pure ∘ f)) ⟩
(fs >>= λ _ → ∅) ≡⟨ MP.right-zero fs ⟩
∅ ∎
unfold-<$> : ∀ {ℓ} {A B : Set ℓ} → (f : A → B) (as : List A) →
(f <$> as) ≡ (pure f ⊛ as)
unfold-<$> f as = ≡.sym (++-identityʳ (f <$> as))
unfold-⊛ : ∀ {ℓ} {A B : Set ℓ} → (fs : List (A → B)) (as : List A) →
(fs ⊛ as) ≡ (fs >>= pam as)
unfold-⊛ fs as = begin
fs ⊛ as
≡⟨ concatMap-cong (λ f → ≡.cong (map f) (concatMap-pure as)) fs ⟨
concatMap (λ f → map f (concatMap pure as)) fs
≡⟨ concatMap-cong (λ f → map-concatMap f pure as) fs ⟩
concatMap (λ f → concatMap (λ x → pure (f x)) as) fs
≡⟨⟩
(fs >>= pam as)
∎
right-distributive : ∀ {ℓ} {A B : Set ℓ} (fs₁ fs₂ : List (A → B)) xs →
((fs₁ ∣ fs₂) ⊛ xs) ≡ (fs₁ ⊛ xs ∣ fs₂ ⊛ xs)
right-distributive fs₁ fs₂ xs = begin
(fs₁ ∣ fs₂) ⊛ xs ≡⟨ unfold-⊛ (fs₁ ∣ fs₂) xs ⟩
(fs₁ ∣ fs₂ >>= pam xs) ≡⟨ MonadProperties.right-distributive fs₁ fs₂ (pam xs) ⟩
(fs₁ >>= pam xs) ∣ (fs₂ >>= pam xs) ≡⟨ ≡.cong₂ _∣_ (unfold-⊛ fs₁ xs) (unfold-⊛ fs₂ xs) ⟨
(fs₁ ⊛ xs ∣ fs₂ ⊛ xs) ∎
private
not-left-distributive :
let fs = id ∷ id ∷ []; xs₁ = true ∷ []; xs₂ = true ∷ false ∷ [] in
(fs ⊛ (xs₁ ∣ xs₂)) ≢ (fs ⊛ xs₁ ∣ fs ⊛ xs₂)
not-left-distributive ()
identity : ∀ {a} {A : Set a} (xs : List A) → (pure id ⊛ xs) ≡ xs
identity xs = begin
pure id ⊛ xs ≡⟨ unfold-⊛ (pure id) xs ⟩
(pure id >>= pam xs) ≡⟨ MonadProperties.left-identity id (pam xs) ⟩
(xs >>= pure) ≡⟨ MonadProperties.right-identity xs ⟩
xs ∎
private
pam-lemma : ∀ {ℓ} {A B C : Set ℓ}
(xs : List A) (f : A → B) (fs : B → List C) →
(pam xs f >>= fs) ≡ (xs >>= λ x → fs (f x))
pam-lemma xs f fs = begin
(pam xs f >>= fs) ≡⟨ MP.associative xs (pure ∘ f) fs ⟨
(xs >>= λ x → pure (f x) >>= fs) ≡⟨ MP.cong (refl {x = xs}) (λ x → MP.left-identity (f x) fs) ⟩
(xs >>= λ x → fs (f x)) ∎
composition : ∀ {ℓ} {A B C : Set ℓ}
(fs : List (B → C)) (gs : List (A → B)) xs →
(pure _∘′_ ⊛ fs ⊛ gs ⊛ xs) ≡ (fs ⊛ (gs ⊛ xs))
composition {ℓ} fs gs xs = begin
pure _∘′_ ⊛ fs ⊛ gs ⊛ xs
≡⟨ unfold-⊛ (pure _∘′_ ⊛ fs ⊛ gs) xs ⟩
(pure _∘′_ ⊛ fs ⊛ gs >>= pam xs)
≡⟨ ≡.cong (_>>= pam xs) (unfold-⊛ (pure _∘′_ ⊛ fs) gs) ⟩
(pure _∘′_ ⊛ fs >>= pam gs >>= pam xs)
≡⟨ ≡.cong (λ h → h >>= pam gs >>= pam xs) (unfold-⊛ (pure _∘′_) fs) ⟩
(pure _∘′_ >>= pam fs >>= pam gs >>= pam xs)
≡⟨ MP.cong (MP.cong (MP.left-identity _∘′_ (pam fs))
(λ f → refl {x = pam gs f}))
(λ fg → refl {x = pam xs fg}) ⟩
(pam fs _∘′_ >>= pam gs >>= pam xs)
≡⟨ MP.cong (pam-lemma fs _∘′_ (pam gs)) (λ _ → refl) ⟩
((fs >>= λ f → pam gs (f ∘′_)) >>= pam xs)
≡⟨ MP.associative fs (λ f → pam gs (_∘′_ f)) (pam xs) ⟨
(fs >>= λ f → pam gs (f ∘′_) >>= pam xs)
≡⟨ MP.cong (refl {x = fs}) (λ f → pam-lemma gs (f ∘′_) (pam xs)) ⟩
(fs >>= λ f → gs >>= λ g → pam xs (f ∘′ g))
≡⟨ (MP.cong (refl {x = fs}) λ f →
MP.cong (refl {x = gs}) λ g →
≡.sym $ pam-lemma xs g (pure ∘ f)) ⟩
(fs >>= λ f → gs >>= λ g → pam (pam xs g) f)
≡⟨ MP.cong (refl {x = fs}) (λ f → MP.associative gs (pam xs) (pure ∘ f)) ⟩
(fs >>= pam (gs >>= pam xs))
≡⟨ unfold-⊛ fs (gs >>= pam xs) ⟨
fs ⊛ (gs >>= pam xs)
≡⟨ ≡.cong (fs ⊛_) (unfold-⊛ gs xs) ⟨
fs ⊛ (gs ⊛ xs)
∎
homomorphism : ∀ {ℓ} {A B : Set ℓ} (f : A → B) x →
(pure f ⊛ pure x) ≡ pure (f x)
homomorphism f x = begin
pure f ⊛ pure x ≡⟨⟩
(pure f >>= pam (pure x)) ≡⟨ MP.left-identity f (pam (pure x)) ⟩
pam (pure x) f ≡⟨ MP.left-identity x (pure ∘ f) ⟩
pure (f x) ∎
interchange : ∀ {ℓ} {A B : Set ℓ} (fs : List (A → B)) {x} →
(fs ⊛ pure x) ≡ (pure (_$′ x) ⊛ fs)
interchange fs {x} = begin
fs ⊛ pure x ≡⟨⟩
(fs >>= pam (pure x)) ≡⟨ (MP.cong (refl {x = fs}) λ f →
MP.left-identity x (pure ∘ f)) ⟩
(fs >>= λ f → pure (f x)) ≡⟨⟩
(pam fs (_$′ x)) ≡⟨ ≡.sym $ MP.left-identity (_$′ x) (pam fs) ⟩
(pure (_$′ x) >>= pam fs) ≡⟨ unfold-⊛ (pure (_$′ x)) fs ⟨
pure (_$′ x) ⊛ fs ∎