1
1
------------------------------------------------------------------------
2
- -- Laws related to _⊛_ and return
2
+ -- Laws related to _⊛_, _<$>_ and return
3
3
------------------------------------------------------------------------
4
4
5
5
module TotalParserCombinators.Laws.ApplicativeFunctor where
6
6
7
7
open import Algebra
8
8
open import Codata.Musical.Notation
9
- open import Data.List
9
+ open import Data.List as List
10
10
import Data.List.Effectful
11
+ import Data.List.Properties as L
11
12
import Data.List.Relation.Binary.BagAndSetEquality as BSEq
12
13
open import Effect.Monad
13
14
open import Function
14
- open import Level
15
-
16
- open RawMonad {f = zero} Data.List.Effectful.monad
17
- using () renaming (_⊛_ to _⊛′_; _>>=_ to _>>=′_)
15
+ import Level
16
+ open import Relation.Binary.PropositionalEquality
17
+ using (module ≡-Reasoning )
18
+
19
+ open RawMonad {f = Level.zero} Data.List.Effectful.monad
20
+ using ()
21
+ renaming (pure to return′;
22
+ _<$>_ to _<$>′_; _⊛_ to _⊛′_; _>>=_ to _>>=′_)
18
23
private
19
24
module BagMonoid {k} {A : Set } =
20
25
CommutativeMonoid (BSEq.commutativeMonoid k A)
@@ -28,6 +33,98 @@ import TotalParserCombinators.Laws.Monad as Monad
28
33
open import TotalParserCombinators.Lib
29
34
open import TotalParserCombinators.Parser
30
35
36
+ private variable
37
+ Tok R R₁ R₂ R₃ : Set
38
+ xs xs₁ : List R
39
+ p p₁ p₂ : Parser Tok R xs
40
+ x : R
41
+ f g : R₁ → R₂
42
+
43
+ ------------------------------------------------------------------------
44
+ -- Some lemmas related to _<$>_
45
+
46
+ module <$> where
47
+
48
+ -- Functor laws (expressed in a certain way).
49
+
50
+ identity : id <$> p ≅P p
51
+ identity {p = p} =
52
+ BagMonoid.reflexive (L.map-id _) ∷ λ t → ♯ (
53
+ id <$> D t p ≅⟨ identity ⟩
54
+ D t p ∎)
55
+
56
+ composition : (f ∘ g) <$> p ≅P f <$> (g <$> p)
57
+ composition {f = f} {g = g} {p = p} =
58
+ BagMonoid.reflexive (L.map-∘ _) ∷ λ t → ♯ (
59
+ (f ∘ g) <$> D t p ≅⟨ composition ⟩
60
+ f <$> (g <$> D t p) ∎)
61
+
62
+ -- The fail combinator is a right zero for _<$>_.
63
+
64
+ zero : f <$> fail ≅P fail {Tok = Tok}
65
+ zero {f = f} =
66
+ BagMonoid.refl ∷ λ _ → ♯ (
67
+ f <$> fail ≅⟨ zero ⟩
68
+ fail ∎)
69
+
70
+ -- A variant of the lemma homomorphism which is defined below.
71
+
72
+ homomorphism : f <$> return x ≅P return {Tok = Tok} (f x)
73
+ homomorphism {f = f} {x = x} =
74
+ BagMonoid.refl ∷ λ _ → ♯ (
75
+ f <$> fail ≅⟨ zero ⟩
76
+ fail ∎)
77
+
78
+ -- The combinator _<$>_ distributes from the left over _∣_.
79
+
80
+ left-distributive :
81
+ {p₁ : Parser Tok R₁ xs₁} →
82
+ f <$> (p₁ ∣ p₂) ≅P f <$> p₁ ∣ f <$> p₂
83
+ left-distributive {xs₁ = xs₁} {f = f} {p₂ = p₂} {p₁ = p₁} =
84
+ BagMonoid.reflexive (L.map-++ _ xs₁ _) ∷ λ t → ♯ (
85
+ f <$> (D t p₁ ∣ D t p₂) ≅⟨ left-distributive ⟩
86
+ f <$> D t p₁ ∣ f <$> D t p₂ ∎)
87
+
88
+ -- The combinator _<$>_ can be expressed using _>>=_ and return.
89
+
90
+ in-terms-of->>= :
91
+ {p : Parser Tok R₁ xs} →
92
+ f <$> p ≅P p >>= (return ∘ f)
93
+ in-terms-of->>= {xs = xs} {f = f} {p = p} =
94
+ BagMonoid.reflexive lemma ∷ λ t → ♯ (
95
+ f <$> D t p ≅⟨ sym (AdditiveMonoid.right-identity _) ⟩
96
+ f <$> D t p ∣ fail ≅⟨ in-terms-of->>= ∣′ sym (Derivative.right-zero->>= _) ⟩
97
+ D t p >>= (return ∘ f) ∣ return⋆ xs >>= (λ _ → fail) ∎)
98
+ where
99
+ open Data.List.Effectful.Applicative
100
+ open Data.List.Effectful.MonadProperties
101
+
102
+ lemma =
103
+ List.map f xs ≡-Reasoning.≡⟨ unfold-<$> _ _ ⟩
104
+ return′ f ⊛′ xs ≡-Reasoning.≡⟨ unfold-⊛ (return′ _) _ ⟩
105
+ (return′ f >>=′ λ f → xs >>=′ return′ ∘ f) ≡-Reasoning.≡⟨ left-identity _ (λ f → xs >>=′ return′ ∘ f) ⟩
106
+ (xs >>=′ return′ ∘ f) ≡-Reasoning.∎
107
+
108
+ -- The combinator _<$>_ can be expressed using _⊛_ and return.
109
+
110
+ in-terms-of-⊛ : f <$> p ≅P return f ⊛ p
111
+ in-terms-of-⊛ {f = f} {p = p} =
112
+ BagMonoid.sym (BagMonoid.identityʳ _) ∷ λ t → ♯ (
113
+ f <$> D t p ≅⟨ in-terms-of-⊛ ⟩
114
+ return f ⊛ D t p ≅⟨ sym $ D-return-⊛ f p ⟩
115
+ D t (return f ⊛ p) ∎)
116
+
117
+ -- A lemma related to _<$>_ and _>>=_.
118
+
119
+ >>=-∘ :
120
+ {p₂ : (x : R₂) → Parser Tok R₃ (g x)} →
121
+ p₁ >>= (p₂ ∘ f) ≅P f <$> p₁ >>= p₂
122
+ >>=-∘ {p₁ = p₁} {f = f} {p₂ = p₂} =
123
+ (p₁ >>= λ x → p₂ (f x)) ≅⟨ ([ ○ - ○ - ○ - ○ ] _ ∎ >>= λ _ → sym $ Monad.left-identity _ _) ⟩
124
+ (p₁ >>= λ x → return (f x) >>= p₂) ≅⟨ Monad.associative _ _ _ ⟩
125
+ p₁ >>= (return ∘ f) >>= p₂ ≅⟨ ([ ○ - ○ - ○ - ○ ] sym in-terms-of->>= >>= λ _ → _ ∎) ⟩
126
+ f <$> p₁ >>= p₂ ∎
127
+
31
128
------------------------------------------------------------------------
32
129
-- _⊛_, return, _∣_ and fail form an applicative functor "with a zero
33
130
-- and a plus"
@@ -36,16 +133,16 @@ open import TotalParserCombinators.Parser
36
133
-- resembles an idempotent semiring (if we restrict ourselves to
37
134
-- language equivalence).
38
135
39
- -- First note that _⊛_ can be defined using _>>=_.
136
+ -- First note that _⊛_ can be defined using _>>=_ and _<$>_ .
40
137
41
138
private
42
139
43
- -- A variant of "flip map".
140
+ -- A flipped variant of "map".
44
141
45
142
pam : ∀ {Tok R₁ R₂ xs} →
46
143
Parser Tok R₁ xs → (f : R₁ → R₂) →
47
- Parser Tok R₂ (xs >>=′ [_] ∘ f )
48
- pam p f = p >>= (return ∘ f)
144
+ Parser Tok R₂ (f <$>′ xs )
145
+ pam p f = f <$> p
49
146
50
147
infixl 10 _⊛″_
51
148
@@ -70,27 +167,12 @@ private
70
167
return⋆ (flatten fs) ⊛ D t (♭? p₂) ≅⟨ ⊛-in-terms-of->>= (D t (♭? p₁)) (♭? p₂) ∣′
71
168
⊛-in-terms-of->>= (return⋆ (flatten fs)) (D t (♭? p₂)) ⟩
72
169
D t (♭? p₁) ⊛″ ♭? p₂ ∣
73
- return⋆ (flatten fs) ⊛″ D t (♭? p₂) ≅⟨ (D t (♭? p₁) ⊛″ ♭? p₂ ∎) ∣′
74
- ([ ○ - ○ - ○ - ○ ] return⋆ (flatten fs) ∎ >>= λ f →
75
- sym $ lemma t f) ⟩
170
+ return⋆ (flatten fs) ⊛″ D t (♭? p₂) ≅⟨ _ ∎ ⟩
171
+
76
172
D t (♭? p₁) >>= pam (♭? p₂) ∣
77
173
return⋆ (flatten fs) >>= (λ f → D t (pam (♭? p₂) f)) ≅⟨ sym $ D->>= (♭? p₁) (pam (♭? p₂)) ⟩
78
174
79
175
D t (♭? p₁ >>= pam (♭? p₂)) ∎)
80
- where
81
- lemma : ∀ t (f : R₁ → R₂) →
82
- D t (♭? p₂ >>= λ x → return (f x)) ≅P
83
- D t (♭? p₂) >>= λ x → return (f x)
84
- lemma t f =
85
- D t (pam (♭? p₂) f) ≅⟨ D->>= (♭? p₂) (return ∘ f) ⟩
86
-
87
- pam (D t (♭? p₂)) f ∣
88
- (return⋆ (flatten xs) >>= λ _ → fail) ≅⟨ (pam (D t (♭? p₂)) f ∎) ∣′
89
- Monad.right-zero (return⋆ (flatten xs)) ⟩
90
- pam (D t (♭? p₂)) f ∣ fail ≅⟨ AdditiveMonoid.right-identity (pam (D t (♭? p₂)) f) ⟩
91
- pam (D t (♭? p₂)) f ∎
92
-
93
- -- We can then reduce all the laws to corresponding laws for _>>=_.
94
176
95
177
-- The zero laws have already been proved.
96
178
@@ -107,9 +189,8 @@ left-distributive : ∀ {Tok R₁ R₂ fs xs₁ xs₂}
107
189
p₁ ⊛ (p₂ ∣ p₃) ≅P p₁ ⊛ p₂ ∣ p₁ ⊛ p₃
108
190
left-distributive p₁ p₂ p₃ =
109
191
p₁ ⊛ (p₂ ∣ p₃) ≅⟨ ⊛-in-terms-of->>= p₁ (p₂ ∣ p₃) ⟩
110
- p₁ ⊛″ (p₂ ∣ p₃) ≅⟨ ([ ○ - ○ - ○ - ○ ] p₁ ∎ >>= λ f →
111
- Monad.right-distributive p₂ p₃ (return ∘ f)) ⟩
112
- (p₁ >>= λ f → pam p₂ f ∣ pam p₃ f) ≅⟨ Monad.left-distributive p₁ (pam p₂) (pam p₃) ⟩
192
+ p₁ ⊛″ (p₂ ∣ p₃) ≅⟨ ([ ○ - ○ - ○ - ○ ] p₁ ∎ >>= λ _ → <$>.left-distributive) ⟩
193
+ (p₁ >>= λ f → f <$> p₂ ∣ f <$> p₃) ≅⟨ Monad.left-distributive p₁ (pam p₂) (pam p₃) ⟩
113
194
p₁ ⊛″ p₂ ∣ p₁ ⊛″ p₃ ≅⟨ sym $ ⊛-in-terms-of->>= p₁ p₂ ∣′
114
195
⊛-in-terms-of->>= p₁ p₃ ⟩
115
196
p₁ ⊛ p₂ ∣ p₁ ⊛ p₃ ∎
@@ -134,15 +215,15 @@ identity : ∀ {Tok R xs} (p : Parser Tok R xs) → return id ⊛ p ≅P p
134
215
identity p =
135
216
return id ⊛ p ≅⟨ ⊛-in-terms-of->>= (return id) p ⟩
136
217
return id ⊛″ p ≅⟨ Monad.left-identity id (pam p) ⟩
137
- p >>= return ≅⟨ Monad.right- identity p ⟩
218
+ id <$> p ≅⟨ <$>. identity ⟩
138
219
p ∎
139
220
140
221
homomorphism : ∀ {Tok R₁ R₂} (f : R₁ → R₂) (x : R₁) →
141
222
return f ⊛ return x ≅P return {Tok = Tok} (f x)
142
223
homomorphism f x =
143
224
return f ⊛ return x ≅⟨ ⊛-in-terms-of->>= (return f) (return x) ⟩
144
225
return f ⊛″ return x ≅⟨ Monad.left-identity f (pam (return x)) ⟩
145
- pam ( return x) f ≅⟨ Monad.left-identity x (return ∘ f) ⟩
226
+ f <$> return x ≅⟨ <$>.homomorphism ⟩
146
227
return (f x) ∎
147
228
148
229
private
@@ -160,48 +241,41 @@ private
160
241
p₃ ⊛ p₄ ≅⟨ ⊛-in-terms-of->>= p₃ p₄ ⟩
161
242
p₃ ⊛″ p₄ ∎
162
243
163
- pam-lemma : ∀ {Tok R₁ R₂ R₃ xs} {g : R₂ → List R₃}
164
- (p₁ : Parser Tok R₁ xs) (f : R₁ → R₂)
165
- (p₂ : (x : R₂) → Parser Tok R₃ (g x)) →
166
- pam p₁ f >>= p₂ ≅P p₁ >>= λ x → p₂ (f x)
167
- pam-lemma p₁ f p₂ =
168
- pam p₁ f >>= p₂ ≅⟨ sym $ Monad.associative p₁ (return ∘ f) p₂ ⟩
169
- (p₁ >>= λ x → return (f x) >>= p₂) ≅⟨ ([ ○ - ○ - ○ - ○ ] p₁ ∎ >>= λ x →
170
- Monad.left-identity (f x) p₂) ⟩
171
- (p₁ >>= λ x → p₂ (f x)) ∎
172
-
173
244
composition :
174
245
∀ {Tok R₁ R₂ R₃ fs gs xs}
175
246
(p₁ : Parser Tok (R₂ → R₃) fs)
176
247
(p₂ : Parser Tok (R₁ → R₂) gs)
177
248
(p₃ : Parser Tok R₁ xs) →
178
249
return _∘′_ ⊛ p₁ ⊛ p₂ ⊛ p₃ ≅P p₁ ⊛ (p₂ ⊛ p₃)
179
250
composition p₁ p₂ p₃ =
180
- return _∘′_ ⊛ p₁ ⊛ p₂ ⊛ p₃ ≅⟨ ⊛-in-terms-of->>= (return _∘′_ ⊛ p₁ ⊛ p₂) p₃ ⟩
181
- return _∘′_ ⊛ p₁ ⊛ p₂ ⊛″ p₃ ≅⟨ ⊛-in-terms-of->>= (return _∘′_ ⊛ p₁) p₂ ⊛-cong (p₃ ∎) ⟩
182
- return _∘′_ ⊛ p₁ ⊛″ p₂ ⊛″ p₃ ≅⟨ ⊛-in-terms-of->>= (return _∘′_) p₁ ⊛-cong (p₂ ∎) ⊛-cong (p₃ ∎) ⟩
183
- return _∘′_ ⊛″ p₁ ⊛″ p₂ ⊛″ p₃ ≅⟨ Monad.left-identity _∘′_ (pam p₁) ⊛-cong (p₂ ∎) ⊛-cong (p₃ ∎) ⟩
184
- pam p₁ _∘′_ ⊛″ p₂ ⊛″ p₃ ≅⟨ pam-lemma p₁ _∘′_ (pam p₂) ⊛-cong (p₃ ∎) ⟩
185
- ((p₁ >>= λ f → pam p₂ (_∘′_ f)) ⊛″ p₃) ≅⟨ sym $ Monad.associative p₁ (λ f → pam p₂ (_∘′_ f)) (pam p₃) ⟩
186
- (p₁ >>= λ f → pam p₂ (_∘′_ f) >>= pam p₃) ≅⟨ ([ ○ - ○ - ○ - ○ ] p₁ ∎ >>= λ f →
187
- pam-lemma p₂ (_∘′_ f) (pam p₃)) ⟩
188
- (p₁ >>= λ f → p₂ >>= λ g → pam p₃ (f ∘′ g)) ≅⟨ ([ ○ - ○ - ○ - ○ ] p₁ ∎ >>= λ f →
189
- [ ○ - ○ - ○ - ○ ] p₂ ∎ >>= λ g →
190
- sym $ pam-lemma p₃ g (return ∘ f)) ⟩
191
- (p₁ >>= λ f → p₂ >>= λ g → pam (pam p₃ g) f) ≅⟨ ([ ○ - ○ - ○ - ○ ] p₁ ∎ >>= λ f →
192
- Monad.associative p₂ (pam p₃) (return ∘ f)) ⟩
193
- p₁ ⊛″ (p₂ ⊛″ p₃) ≅⟨ sym $ (p₁ ∎) ⊛-cong ⊛-in-terms-of->>= p₂ p₃ ⟩
194
- p₁ ⊛″ (p₂ ⊛ p₃) ≅⟨ sym $ ⊛-in-terms-of->>= p₁ (p₂ ⊛ p₃) ⟩
195
- p₁ ⊛ (p₂ ⊛ p₃) ∎
251
+ return _∘′_ ⊛ p₁ ⊛ p₂ ⊛ p₃ ≅⟨ ⊛-in-terms-of->>= (return _∘′_ ⊛ p₁ ⊛ p₂) p₃ ⟩
252
+ return _∘′_ ⊛ p₁ ⊛ p₂ ⊛″ p₃ ≅⟨ ⊛-in-terms-of->>= (return _∘′_ ⊛ p₁) p₂ ⊛-cong (p₃ ∎) ⟩
253
+ return _∘′_ ⊛ p₁ ⊛″ p₂ ⊛″ p₃ ≅⟨ ⊛-in-terms-of->>= (return _∘′_) p₁ ⊛-cong (p₂ ∎) ⊛-cong (p₃ ∎) ⟩
254
+ return _∘′_ ⊛″ p₁ ⊛″ p₂ ⊛″ p₃ ≅⟨ Monad.left-identity _∘′_ (pam p₁) ⊛-cong (p₂ ∎) ⊛-cong (p₃ ∎) ⟩
255
+ _∘′_ <$> p₁ ⊛″ p₂ ⊛″ p₃ ≅⟨ _ ∎ ⟩
256
+ (_∘′_ <$> p₁ >>= _<$> p₂) >>= _<$> p₃ ≅⟨ ([ ○ - ○ - ○ - ○ ] sym <$>.>>=-∘ >>= λ _ → _ ∎) ⟩
257
+ (p₁ >>= λ f → (f ∘′_) <$> p₂) >>= _<$> p₃ ≅⟨ sym $ Monad.associative _ _ _ ⟩
258
+ (p₁ >>= λ f → (f ∘′_) <$> p₂ >>= _<$> p₃) ≅⟨ ([ ○ - ○ - ○ - ○ ] _ ∎ >>= λ _ → sym <$>.>>=-∘) ⟩
259
+ (p₁ >>= λ f → p₂ >>= λ g → (f ∘′ g) <$> p₃) ≅⟨ ([ ○ - ○ - ○ - ○ ] _ ∎ >>= λ _ →
260
+ [ ○ - ○ - ○ - ○ ] _ ∎ >>= λ _ →
261
+ <$>.composition) ⟩
262
+ (p₁ >>= λ f → p₂ >>= λ g → f <$> (g <$> p₃)) ≅⟨ ([ ○ - ○ - ○ - ○ ] _ ∎ >>= λ _ →
263
+ [ ○ - ○ - ○ - ○ ] _ ∎ >>= λ _ →
264
+ <$>.in-terms-of->>=) ⟩
265
+ (p₁ >>= λ f → p₂ >>= λ g → g <$> p₃ >>= (return ∘ f)) ≅⟨ ([ ○ - ○ - ○ - ○ ] _ ∎ >>= λ _ → Monad.associative _ _ _) ⟩
266
+ (p₁ >>= λ f → p₂ >>= _<$> p₃ >>= (return ∘ f)) ≅⟨ ([ ○ - ○ - ○ - ○ ] _ ∎ >>= λ _ → sym <$>.in-terms-of->>=) ⟩
267
+ (p₁ >>= λ f → f <$> (p₂ >>= _<$> p₃)) ≅⟨ _ ∎ ⟩
268
+ p₁ ⊛″ (p₂ ⊛″ p₃) ≅⟨ sym $ (p₁ ∎) ⊛-cong ⊛-in-terms-of->>= p₂ p₃ ⟩
269
+ p₁ ⊛″ (p₂ ⊛ p₃) ≅⟨ sym $ ⊛-in-terms-of->>= p₁ (p₂ ⊛ p₃) ⟩
270
+ p₁ ⊛ (p₂ ⊛ p₃) ∎
196
271
197
272
interchange : ∀ {Tok R₁ R₂ fs}
198
273
(p : Parser Tok (R₁ → R₂) fs) (x : R₁) →
199
274
p ⊛ return x ≅P return (λ f → f x) ⊛ p
200
275
interchange p x =
201
276
p ⊛ return x ≅⟨ ⊛-in-terms-of->>= p (return x) ⟩
202
- p ⊛″ return x ≅⟨ ([ ○ - ○ - ○ - ○ ] p ∎ >>= λ f →
203
- Monad.left-identity x (return ∘ f)) ⟩
204
- (p >>= λ f → return (f x)) ≅⟨ pam p (λ f → f x) ∎ ⟩
205
- pam p (λ f → f x) ≅⟨ sym $ Monad.left-identity (λ f → f x) (pam p) ⟩
277
+ p ⊛″ return x ≅⟨ ([ ○ - ○ - ○ - ○ ] p ∎ >>= λ _ → <$>.homomorphism) ⟩
278
+ (p >>= λ f → return (f x)) ≅⟨ sym <$>.in-terms-of->>= ⟩
279
+ (λ f → f x) <$> p ≅⟨ sym $ Monad.left-identity (λ f → f x) (pam p) ⟩
206
280
return (λ f → f x) ⊛″ p ≅⟨ sym $ ⊛-in-terms-of->>= (return (λ f → f x)) p ⟩
207
281
return (λ f → f x) ⊛ p ∎
0 commit comments