Skip to content

Commit 501017f

Browse files
Chapter18: Add
1 parent 200a114 commit 501017f

File tree

6 files changed

+239
-3
lines changed

6 files changed

+239
-3
lines changed

Function/Equivalence/Reasoning.agda

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ infix 3 _∎
2727
begin_ : {A : Set a} {B : Set b} A ⇔ B A ⇔ B
2828
begin A⇔B = A⇔B
2929

30-
_∎ : (A : Set a) A ⇔ A
30+
_∎ : (A : Set a) A ⇔ A
3131
_∎ = id-⇔
3232

3333
_⇔⟨⟩_ : (A : Set a) {B : Set b} A ⇔ B A ⇔ B

Mockingbird/Forest/Combination/Base.agda

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ private
1515

1616
-- If P is a set of birds, we can think of ⟨ P ⟩ as the set of birds ‘generated
1717
-- by’ P.
18-
data ⟨_⟩ (P : Pred Bird p) : Bird Set (p ⊔ b ⊔ ℓ) where
18+
data ⟨_⟩ (P : Pred Bird p) : Pred Bird (p ⊔ b ⊔ ℓ) where
1919
[_] : (x∈P : x ∈ P) x ∈ ⟨ P ⟩
2020

2121
_⟨∙⟩_∣_ :

Mockingbird/Forest/Combination/Properties.agda

+3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ subst′ respects y≈x = subst respects (sym y≈x)
3232
⟨ P ⟩⊆⟨ Q ⟩ P⊆Q [ x∈P ] = [ P⊆Q x∈P ]
3333
⟨ P ⟩⊆⟨ Q ⟩ P⊆Q (x∈⟨P⟩ ⟨∙⟩ y∈⟨P⟩ ∣ xy≈z) = ⟨ P ⟩⊆⟨ Q ⟩ P⊆Q x∈⟨P⟩ ⟨∙⟩ ⟨ P ⟩⊆⟨ Q ⟩ P⊆Q y∈⟨P⟩ ∣ xy≈z
3434

35+
weaken : {p} {P Q : Pred Bird p} P ⊆ Q ⟨ P ⟩ ⊆ ⟨ Q ⟩
36+
weaken {P = P} {Q} = ⟨ P ⟩⊆⟨ Q ⟩
37+
3538
⟨_∩_⟩ : {p} (P Q : Pred Bird p) ⟨ (P ∩ Q) ⟩ ⊆ ⟨ P ⟩ ∩ ⟨ Q ⟩
3639
⟨ P ∩ Q ⟩ [ (x∈P , x∈Q) ] = ([ x∈P ] , [ x∈Q ])
3740
⟨ P ∩ Q ⟩ (_⟨∙⟩_∣_ {x} {y} {z} x∈⟨P∩Q⟩ y∈⟨P∩Q⟩ xy≈z) =

Mockingbird/Forest/Combination/Vec/Properties.agda

+19-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ open import Mockingbird.Forest using (Forest)
22

33
module Mockingbird.Forest.Combination.Vec.Properties {b ℓ} (forest : Forest {b} {ℓ}) where
44

5-
open import Data.Vec as Vec using (Vec; []; _∷_)
5+
open import Data.Vec as Vec using (Vec; []; _∷_; _++_)
66
import Data.Vec.Relation.Unary.Any as Any
7+
open import Data.Vec.Relation.Unary.Any.Properties as Anyₚ using (++⁺ˡ; ++⁺ʳ)
78
open import Function using (_$_; flip)
89
open import Relation.Unary using (Pred; _∈_; _⊆_; ∅)
910

@@ -21,6 +22,23 @@ subst′ y≈x = subst (sym y≈x)
2122
⟨[]⟩ : ⟨ [] ⟩ ⊆ ∅
2223
⟨[]⟩ (X ⟨∙⟩ Y ∣ xy≈z) = ⟨[]⟩ X
2324

25+
weaken-∷ : {n x y} {bs : Vec Bird n} x ∈ ⟨ bs ⟩ x ∈ ⟨ y ∷ bs ⟩
26+
weaken-∷ = Combinationₚ.weaken there
27+
28+
-- TODO: maybe call this ++⁺ˡ.
29+
weaken-++ˡ : {m n x} {bs : Vec Bird m} {bs′ : Vec Bird n} x ∈ ⟨ bs ⟩ x ∈ ⟨ bs ++ bs′ ⟩
30+
weaken-++ˡ {bs = bs} {bs′} [ x∈bs ] = [ ++⁺ˡ x∈bs ]
31+
weaken-++ˡ {bs = bs} {bs′} (x∈⟨bs⟩ ⟨∙⟩ y∈⟨bs⟩ ∣ xy≈z) = weaken-++ˡ x∈⟨bs⟩ ⟨∙⟩ weaken-++ˡ y∈⟨bs⟩ ∣ xy≈z
32+
33+
-- TODO: maybe call this ++⁺ʳ.
34+
weaken-++ʳ : {m n x} (bs : Vec Bird m) {bs′ : Vec Bird n} x ∈ ⟨ bs′ ⟩ x ∈ ⟨ bs ++ bs′ ⟩
35+
weaken-++ʳ bs {bs′} [ x∈bs′ ] = [ ++⁺ʳ bs x∈bs′ ]
36+
weaken-++ʳ bs {bs′} (x∈⟨bs′⟩ ⟨∙⟩ y∈⟨bs′⟩ ∣ xy≈z) = weaken-++ʳ bs x∈⟨bs′⟩ ⟨∙⟩ weaken-++ʳ bs y∈⟨bs′⟩ ∣ xy≈z
37+
38+
++-comm : {m n x} (bs : Vec Bird m) (bs′ : Vec Bird n) x ∈ ⟨ bs ++ bs′ ⟩ x ∈ ⟨ bs′ ++ bs ⟩
39+
++-comm bs bs′ [ x∈bs++bs′ ] = [ Anyₚ.++-comm bs bs′ x∈bs++bs′ ]
40+
++-comm bs bs′ (x∈⟨bs++bs′⟩ ⟨∙⟩ y∈⟨bs++bs′⟩ ∣ xy≈z) = ++-comm bs bs′ x∈⟨bs++bs′⟩ ⟨∙⟩ ++-comm bs bs′ y∈⟨bs++bs′⟩ ∣ xy≈z
41+
2442
open import Mockingbird.Forest.Birds forest
2543
open import Mockingbird.Forest.Extensionality forest
2644
module _ ⦃ _ : Extensional ⦄ ⦃ _ : HasCardinal ⦄ ⦃ _ : HasIdentity ⦄

Mockingbird/Problems/Chapter18.agda

+214
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
open import Mockingbird.Forest using (Forest)
2+
import Mockingbird.Forest.Birds as Birds
3+
4+
-- The Master Forest
5+
module Mockingbird.Problems.Chapter18 {b ℓ} (forest : Forest {b} {ℓ})
6+
⦃ _ : Birds.HasStarling forest ⦄
7+
⦃ _ : Birds.HasKestrel forest ⦄ where
8+
9+
open import Data.Maybe using (Maybe; nothing; just)
10+
open import Data.Product using (_×_; _,_; proj₁; ∃-syntax)
11+
open import Data.Vec using (Vec; []; _∷_; _++_)
12+
open import Data.Vec.Relation.Unary.Any.Properties using (++⁺ʳ)
13+
open import Function using (_$_)
14+
open import Level using (_⊔_)
15+
open import Mockingbird.Forest.Combination.Vec forest using (⟨_⟩; here; there; [_]; _⟨∙⟩_∣_; _⟨∙⟩_; [#_])
16+
open import Mockingbird.Forest.Combination.Vec.Properties forest using (subst′; weaken-++ˡ; weaken-++ʳ; ++-comm)
17+
open import Relation.Unary using (_∈_)
18+
19+
open Forest forest
20+
open import Mockingbird.Forest.Birds forest
21+
22+
problem₁ : HasIdentity
23+
problem₁ = record
24+
{ I = S ∙ K ∙ K
25+
; isIdentity = λ x begin
26+
S ∙ K ∙ K ∙ x ≈⟨ isStarling K K x ⟩
27+
K ∙ x ∙ (K ∙ x) ≈⟨ isKestrel x (K ∙ x) ⟩
28+
x ∎
29+
}
30+
31+
private instance hasIdentity = problem₁
32+
33+
problem₂ : HasMockingbird
34+
problem₂ = record
35+
{ M = S ∙ I ∙ I
36+
; isMockingbird = λ x begin
37+
S ∙ I ∙ I ∙ x ≈⟨ isStarling I I x ⟩
38+
I ∙ x ∙ (I ∙ x) ≈⟨ congʳ $ isIdentity x ⟩
39+
x ∙ (I ∙ x) ≈⟨ congˡ $ isIdentity x ⟩
40+
x ∙ x ∎
41+
}
42+
43+
private instance hasMockingbird = problem₂
44+
45+
problem₃ : HasThrush
46+
problem₃ = record
47+
{ T = S ∙ (K ∙ (S ∙ I)) ∙ K
48+
; isThrush = λ x y begin
49+
S ∙ (K ∙ (S ∙ I)) ∙ K ∙ x ∙ y ≈⟨ congʳ $ isStarling (K ∙ (S ∙ I)) K x ⟩
50+
K ∙ (S ∙ I) ∙ x ∙ (K ∙ x) ∙ y ≈⟨ (congʳ $ congʳ $ isKestrel (S ∙ I) x) ⟩
51+
S ∙ I ∙ (K ∙ x) ∙ y ≈⟨ isStarling I (K ∙ x) y ⟩
52+
I ∙ y ∙ (K ∙ x ∙ y) ≈⟨ congʳ $ isIdentity y ⟩
53+
y ∙ (K ∙ x ∙ y) ≈⟨ congˡ $ isKestrel x y ⟩
54+
y ∙ x ∎
55+
}
56+
57+
-- TODO: Problem 4.
58+
59+
I∈⟨S,K⟩ : I ∈ ⟨ S ∷ K ∷ [] ⟩
60+
I∈⟨S,K⟩ = subst′ refl $ [# 0 ] ⟨∙⟩ [# 1 ] ⟨∙⟩ [# 1 ]
61+
62+
-- Try to strengthen a proof of X ∈ ⟨ y ∷ xs ⟩ to X ∈ ⟨ xs ⟩, which can be done
63+
-- if y does not occur in X.
64+
strengthen : {n X y} {xs : Vec Bird n} X ∈ ⟨ y ∷ xs ⟩ Maybe (X ∈ ⟨ xs ⟩)
65+
-- NOTE: it could be the case that y ∈ xs, but checking that requires decidable
66+
-- equality.
67+
strengthen [ here X≈y ] = nothing
68+
strengthen [ there X∈xs ] = just [ X∈xs ]
69+
strengthen (Y∈⟨y,xs⟩ ⟨∙⟩ Z∈⟨y,xs⟩ ∣ YZ≈X) = do
70+
Y∈⟨xs⟩ strengthen Y∈⟨y,xs⟩
71+
Z∈⟨xs⟩ strengthen Z∈⟨y,xs⟩
72+
just $ Y∈⟨xs⟩ ⟨∙⟩ Z∈⟨xs⟩ ∣ YZ≈X
73+
where
74+
open import Data.Maybe.Categorical using (monad)
75+
open import Category.Monad using (RawMonad)
76+
open RawMonad (monad {b ⊔ ℓ})
77+
78+
eliminate : {n X y} {xs : Vec Bird n} X ∈ ⟨ y ∷ xs ⟩ ∃[ X′ ] (X′ ∈ ⟨ S ∷ K ∷ xs ⟩ × X′ ∙ y ≈ X)
79+
eliminate {X = X} {y} [ here X≈y ] = (I , weaken-++ˡ I∈⟨S,K⟩ , trans (isIdentity y) (sym X≈y))
80+
eliminate {X = X} {y} [ there X∈xs ] = (K ∙ X , [# 1 ] ⟨∙⟩ [ ++⁺ʳ (S ∷ K ∷ []) X∈xs ] , isKestrel X y)
81+
eliminate {X = X} {y} (_⟨∙⟩_∣_ {Y} {Z} Y∈⟨y,xs⟩ [ here Z≈y ] YZ≈X) with strengthen Y∈⟨y,xs⟩
82+
... | just Y∈⟨xs⟩ = (Y , weaken-++ʳ (S ∷ K ∷ []) Y∈⟨xs⟩ , trans (congˡ (sym Z≈y)) YZ≈X)
83+
... | nothing =
84+
let (Y′ , Y′∈⟨S,K,xs⟩ , Y′y≈Y) = eliminate Y∈⟨y,xs⟩
85+
86+
SY′Iy≈X : S ∙ Y′ ∙ I ∙ y ≈ X
87+
SY′Iy≈X = begin
88+
S ∙ Y′ ∙ I ∙ y ≈⟨ isStarling Y′ I y ⟩
89+
Y′ ∙ y ∙ (I ∙ y) ≈⟨ congʳ $ Y′y≈Y ⟩
90+
Y ∙ (I ∙ y) ≈⟨ congˡ $ isIdentity y ⟩
91+
Y ∙ y ≈˘⟨ congˡ Z≈y ⟩
92+
Y ∙ Z ≈⟨ YZ≈X ⟩
93+
X ∎
94+
in (S ∙ Y′ ∙ I , [# 0 ] ⟨∙⟩ Y′∈⟨S,K,xs⟩ ⟨∙⟩ weaken-++ˡ I∈⟨S,K⟩ , SY′Iy≈X)
95+
eliminate {X = X} {y} (_⟨∙⟩_∣_ {Y} {Z} Y∈⟨y,xs⟩ Z∈⟨y,xs⟩ YZ≈X) =
96+
let (Y′ , Y′∈⟨S,K,xs⟩ , Y′y≈Y) = eliminate Y∈⟨y,xs⟩
97+
(Z′ , Z′∈⟨S,K,xs⟩ , Z′y≈Z) = eliminate Z∈⟨y,xs⟩
98+
99+
SY′Z′y≈X : S ∙ Y′ ∙ Z′ ∙ y ≈ X
100+
SY′Z′y≈X = begin
101+
S ∙ Y′ ∙ Z′ ∙ y ≈⟨ isStarling Y′ Z′ y ⟩
102+
Y′ ∙ y ∙ (Z′ ∙ y) ≈⟨ congʳ Y′y≈Y ⟩
103+
Y ∙ (Z′ ∙ y) ≈⟨ congˡ Z′y≈Z ⟩
104+
Y ∙ Z ≈⟨ YZ≈X ⟩
105+
X ∎
106+
in (S ∙ Y′ ∙ Z′ , [# 0 ] ⟨∙⟩ Y′∈⟨S,K,xs⟩ ⟨∙⟩ Z′∈⟨S,K,xs⟩ , SY′Z′y≈X)
107+
108+
module _ (x y : Bird) where
109+
-- Example: y-eliminating the expression y should give I.
110+
_ : proj₁ (eliminate {y = y} {xs = x ∷ []} $ [# 0 ]) ≈ I
111+
_ = refl
112+
113+
-- Example: y-eliminating the expression x should give Kx.
114+
_ : proj₁ (eliminate {y = y} {xs = x ∷ []} $ [# 1 ]) ≈ K ∙ x
115+
_ = refl
116+
117+
-- Example: y-eliminating the expression xy should give x (Principle 3).
118+
_ : proj₁ (eliminate {y = y} {xs = x ∷ []} $ [# 1 ] ⟨∙⟩ [# 0 ]) ≈ x
119+
_ = refl
120+
121+
-- Example: y-eliminating the expression yx should give SI(Kx).
122+
_ : proj₁ (eliminate {y = y} {xs = x ∷ []} $ [# 0 ] ⟨∙⟩ [# 1 ]) ≈ S ∙ I ∙ (K ∙ x)
123+
_ = refl
124+
125+
-- Example: y-eliminating the expression yy should give SII.
126+
_ : proj₁ (eliminate {y = y} {xs = x ∷ []} $ [# 0 ] ⟨∙⟩ [# 0 ]) ≈ S ∙ I ∙ I
127+
_ = refl
128+
129+
strengthen-SK : {n X y} {xs : Vec Bird n} X ∈ ⟨ S ∷ K ∷ y ∷ xs ⟩ Maybe (X ∈ ⟨ S ∷ K ∷ xs ⟩)
130+
strengthen-SK {y = y} {xs} X∈⟨S,K,y,xs⟩ = do
131+
let X∈⟨y,xs,S,K⟩ = ++-comm (S ∷ K ∷ []) (y ∷ xs) X∈⟨S,K,y,xs⟩
132+
X∈⟨xs,S,K⟩ strengthen X∈⟨y,xs,S,K⟩
133+
let X∈⟨S,K,xs⟩ = ++-comm xs (S ∷ K ∷ []) X∈⟨xs,S,K⟩
134+
just X∈⟨S,K,xs⟩
135+
where
136+
open import Data.Maybe.Categorical using (monad)
137+
open import Category.Monad using (RawMonad)
138+
open RawMonad (monad {b ⊔ ℓ})
139+
140+
-- TODO: formulate eliminate or eliminate-SK in terms of the other.
141+
eliminate-SK : {n X y} {xs : Vec Bird n} X ∈ ⟨ S ∷ K ∷ y ∷ xs ⟩ ∃[ X′ ] (X′ ∈ ⟨ S ∷ K ∷ xs ⟩ × X′ ∙ y ≈ X)
142+
eliminate-SK {X = X} {y} [ here X≈S ] = (K ∙ S , [# 1 ] ⟨∙⟩ [# 0 ] , trans (isKestrel S y) (sym X≈S))
143+
eliminate-SK {X = X} {y} [ there (here X≈K) ] = (K ∙ K , [# 1 ] ⟨∙⟩ [# 1 ] , trans (isKestrel K y) (sym X≈K))
144+
eliminate-SK {X = X} {y} [ there (there (here X≈y)) ] = (I , weaken-++ˡ I∈⟨S,K⟩ , trans (isIdentity y) (sym X≈y))
145+
eliminate-SK {X = X} {y} [ there (there (there X∈xs)) ] = (K ∙ X , ([# 1 ] ⟨∙⟩ [ (++⁺ʳ (S ∷ K ∷ []) X∈xs) ]) , isKestrel X y)
146+
eliminate-SK {X = X} {y} (_⟨∙⟩_∣_ {Y} {Z} Y∈⟨S,K,y,xs⟩ [ there (there (here Z≈y)) ] YZ≈X) with strengthen-SK Y∈⟨S,K,y,xs⟩
147+
... | just Y∈⟨S,K,xs⟩ = (Y , Y∈⟨S,K,xs⟩ , trans (congˡ (sym Z≈y)) YZ≈X)
148+
... | nothing =
149+
let (Y′ , Y′∈⟨S,K,xs⟩ , Y′y≈Y) = eliminate-SK Y∈⟨S,K,y,xs⟩
150+
151+
SY′Iy≈X : S ∙ Y′ ∙ I ∙ y ≈ X
152+
SY′Iy≈X = begin
153+
S ∙ Y′ ∙ I ∙ y ≈⟨ isStarling Y′ I y ⟩
154+
Y′ ∙ y ∙ (I ∙ y) ≈⟨ congʳ $ Y′y≈Y ⟩
155+
Y ∙ (I ∙ y) ≈⟨ congˡ $ isIdentity y ⟩
156+
Y ∙ y ≈˘⟨ congˡ Z≈y ⟩
157+
Y ∙ Z ≈⟨ YZ≈X ⟩
158+
X ∎
159+
in (S ∙ Y′ ∙ I , [# 0 ] ⟨∙⟩ Y′∈⟨S,K,xs⟩ ⟨∙⟩ weaken-++ˡ I∈⟨S,K⟩ , SY′Iy≈X)
160+
eliminate-SK {X = X} {y} (_⟨∙⟩_∣_ {Y} {Z} Y∈⟨S,K,y,xs⟩ Z∈⟨S,K,y,xs⟩ YZ≈X) =
161+
let (Y′ , Y′∈⟨S,K,xs⟩ , Y′y≈Y) = eliminate-SK Y∈⟨S,K,y,xs⟩
162+
(Z′ , Z′∈⟨S,K,xs⟩ , Z′y≈Z) = eliminate-SK Z∈⟨S,K,y,xs⟩
163+
164+
SY′Z′y≈X : S ∙ Y′ ∙ Z′ ∙ y ≈ X
165+
SY′Z′y≈X = begin
166+
S ∙ Y′ ∙ Z′ ∙ y ≈⟨ isStarling Y′ Z′ y ⟩
167+
Y′ ∙ y ∙ (Z′ ∙ y) ≈⟨ congʳ Y′y≈Y ⟩
168+
Y ∙ (Z′ ∙ y) ≈⟨ congˡ Z′y≈Z ⟩
169+
Y ∙ Z ≈⟨ YZ≈X ⟩
170+
X ∎
171+
in (S ∙ Y′ ∙ Z′ , [# 0 ] ⟨∙⟩ Y′∈⟨S,K,xs⟩ ⟨∙⟩ Z′∈⟨S,K,xs⟩ , SY′Z′y≈X)
172+
173+
module _ (x y : Bird) where
174+
-- Example: y-eliminating the expression y should give I.
175+
_ : proj₁ (eliminate-SK {y = y} {xs = x ∷ []} $ [# 2 ]) ≈ I
176+
_ = refl
177+
178+
-- Example: y-eliminating the expression x should give Kx.
179+
_ : proj₁ (eliminate-SK {y = y} {xs = x ∷ []} $ [# 3 ]) ≈ K ∙ x
180+
_ = refl
181+
182+
-- Example: y-eliminating the expression xy should give x (Principle 3).
183+
_ : proj₁ (eliminate-SK {y = y} {xs = x ∷ []} $ [# 3 ] ⟨∙⟩ [# 2 ]) ≈ x
184+
_ = refl
185+
186+
-- Example: y-eliminating the expression yx should give SI(Kx).
187+
_ : proj₁ (eliminate-SK {y = y} {xs = x ∷ []} $ [# 2 ] ⟨∙⟩ [# 3 ]) ≈ S ∙ I ∙ (K ∙ x)
188+
_ = refl
189+
190+
-- Example: y-eliminating the expression yy should give SII.
191+
_ : proj₁ (eliminate-SK {y = y} {xs = x ∷ []} $ [# 2 ] ⟨∙⟩ [# 2 ]) ≈ S ∙ I ∙ I
192+
_ = refl
193+
194+
infixl 6 _∙ⁿ_
195+
_∙ⁿ_ : {n} (A : Bird) (xs : Vec Bird n) Bird
196+
A ∙ⁿ [] = A
197+
A ∙ⁿ (x ∷ xs) = A ∙ⁿ xs ∙ x
198+
199+
eliminateAll′ : {n X} {xs : Vec Bird n} X ∈ ⟨ S ∷ K ∷ xs ⟩ ∃[ X′ ] (X′ ∈ ⟨ S ∷ K ∷ [] ⟩ × X′ ∙ⁿ xs ≈ X)
200+
eliminateAll′ {X = X} {[]} X∈⟨S,K⟩ = (X , X∈⟨S,K⟩ , refl)
201+
eliminateAll′ {X = X} {x ∷ xs} X∈⟨S,K,x,xs⟩ =
202+
let (X′ , X′∈⟨S,K,xs⟩ , X′x≈X) = eliminate-SK X∈⟨S,K,x,xs⟩
203+
(X″ , X″∈⟨S,K⟩ , X″xs≈X′) = eliminateAll′ X′∈⟨S,K,xs⟩
204+
205+
X″∙ⁿxs∙x≈X : X″ ∙ⁿ xs ∙ x ≈ X
206+
X″∙ⁿxs∙x≈X = begin
207+
X″ ∙ⁿ xs ∙ x ≈⟨ congʳ X″xs≈X′ ⟩
208+
X′ ∙ x ≈⟨ X′x≈X ⟩
209+
X ∎
210+
in (X″ , X″∈⟨S,K⟩ , X″∙ⁿxs∙x≈X)
211+
212+
-- TOOD: can we do this in some way without depending on xs : Vec Bird n?
213+
eliminateAll : {n X} {xs : Vec Bird n} X ∈ ⟨ xs ⟩ ∃[ X′ ] (X′ ∈ ⟨ S ∷ K ∷ [] ⟩ × X′ ∙ⁿ xs ≈ X)
214+
eliminateAll X∈⟨xs⟩ = eliminateAll′ $ weaken-++ʳ (S ∷ K ∷ []) X∈⟨xs⟩

index.agda

+1
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@ import Mockingbird.Problems.Chapter14
2929
import Mockingbird.Problems.Chapter15
3030
import Mockingbird.Problems.Chapter16
3131
import Mockingbird.Problems.Chapter17
32+
import Mockingbird.Problems.Chapter18

0 commit comments

Comments
 (0)