Skip to content

Commit a1065df

Browse files
committed
[ new ] Tactic.Cong
1 parent 82d5f19 commit a1065df

File tree

6 files changed

+464
-1
lines changed

6 files changed

+464
-1
lines changed

CHANGELOG.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@ Other major additions
4747
Reflection.TypeChecking.Monad
4848
Reflection.TypeChecking.Monad.Categorical
4949
Reflection.TypeChecking.Monad.Instances
50-
```
50+
```
51+
52+
* Function application in reflected terms (`Reflection.Apply`)
53+
54+
* Congruence helper macros in `Tactic.Cong`
5155
5256
Other major changes
5357
-------------------
@@ -57,3 +61,4 @@ Other minor additions
5761
5862
* Made first argument of [,]-∘-distr in `Data.Sum.Properties` explicit
5963
* Added map-id, map₁₂-commute, [,]-cong, [-,]-cong, [,-]-cong, map-cong, map₁-cong and map₂-cong to `Data.Sum.Properties`
64+
* `Reflection.Pattern`: Calculation of number of bound variables in patterns with `pattern-size` and `pattern-args-size`

README/Tactic/Cong.agda

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{-# OPTIONS --without-K #-}
2+
3+
module README.Tactic.Cong where
4+
5+
-- Tactic.Cong provides a helper macro for using congruence when reasoning about
6+
-- relations. It allows the "hole" that you are operating in to be inferred from
7+
-- the relation instance you are operating on, through use of ⌊_⌋.
8+
9+
-- Tactic.Cong is inspired by the agda-holes project.
10+
11+
-- For this README, the relation used is _≡_, though any (non-dependent) relation
12+
-- with congruence and transitivity defined should work
13+
open import Relation.Binary.PropositionalEquality
14+
open ≡-Reasoning
15+
16+
--import this to use ⌊_⌋
17+
open import Tactic.Cong.Id
18+
19+
-- import this to use ⌊⌋ , lhs , rhs and _≡⌊_⌋_
20+
-- Arguments supplied:
21+
-- * Recursion upper limit when evaluating reflected terms - typically does not
22+
-- need to be large, and mostly depends on the cong and trans supplied, not
23+
-- the equations you want to use this in.
24+
-- * Relation that congruence operates over
25+
-- * The congruence definition itself
26+
-- * Transitivity definition for _≡_. Needed for _≡⌊_⌋_
27+
open import Tactic.Cong 1 _≡_ cong trans
28+
29+
-- To use this tactic with _≡_ and cong from Cubical Agda, use
30+
-- something like the following:
31+
--
32+
-- open import Tactic.Cong 2 _≡_ (λ f p → cong f p) _∙_
33+
34+
-- The following proofs show example uses of the macros ⌊⌋ and _≡⌊_⌋_
35+
-- See Tactic.Cong for more details of how to use these macros
36+
37+
open import Data.Integer
38+
open import Data.Integer.Properties
39+
open import Function.Base
40+
41+
foo : (a b c d : ℤ) (a + b) * (c + d) ≡ a * c + a * d + b * c + b * d
42+
foo a b c d = begin
43+
(a + b) * (c + d) ≡⟨ *-distribˡ-+ (a + b) _ _ ⟩
44+
⌊ (a + b) * c ⌋ + (a + b) * d ≡⌊ *-distribʳ-+ c a b ⌋
45+
a * c + b * c + ⌊ (a + b) * d ⌋ ≡⌊ *-distribʳ-+ d a b ⌋
46+
a * c + b * c + (a * d + b * d) ≡⟨ +-assoc (a * c) _ _ ⟩
47+
a * c + ⌊ b * c + (a * d + b * d)⌋ ≡⌊ +-comm (b * c) _ ⌋
48+
a * c + ((a * d + b * d) + b * c) ≡⟨ sym $ +-assoc (a * c) _ _ ⟩
49+
⌊ a * c + (a * d + b * d) ⌋ + b * c ≡⌊ sym $ +-assoc (a * c) _ _ ⌋
50+
a * c + a * d + b * d + b * c ≡⟨ +-assoc (a * c + a * d) _ _ ⟩
51+
a * c + a * d + ⌊ b * d + b * c ⌋ ≡⌊ +-comm (b * d) _ ⌋
52+
a * c + a * d + (b * c + b * d) ≡⟨ sym $ +-assoc (a * c + a * d) _ _ ⟩
53+
a * c + a * d + b * c + b * d ∎
54+
55+
bar : (a b c : ℤ) a + b + c ≡ b + a + c
56+
bar a b c = begin
57+
⌊ a + b ⌋ + c ≡⌊ +-comm a b ⌋
58+
b + a + c ∎
59+
60+
baz : (a b c : ℤ) ⌊ a + b ⌋ + c ≡ b + a + c
61+
baz a b c = ⌊⌋ lhs (+-comm a b)

src/Reflection/Apply.agda

+194
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
{-# OPTIONS --without-K --safe #-}
2+
3+
open import Data.Nat
4+
5+
module Reflection.Apply (limit : ℕ) where
6+
7+
open import Level renaming (suc to lsuc; _⊔_ to lmax)
8+
open import Data.List
9+
open import Data.Sum.Base
10+
open import Data.Product
11+
open import Function.Base
12+
open import Data.Nat.Base
13+
open import Relation.Nullary
14+
open import Data.Bool.Base
15+
open import Reflection hiding (map-Args ; returnTC ; _≟_ ; _>>=_) renaming (return to returnTC)
16+
open import Reflection.Argument
17+
open import Reflection.Argument.Visibility using () renaming (_≟_ to _≟ᵥ_)
18+
open import Reflection.Pattern hiding (_≟_)
19+
open import Reflection.Term
20+
open import Data.Maybe.Base hiding (_>>=_)
21+
22+
Result : Set 0ℓ Set 0ℓ
23+
Result A = List ErrorPart ⊎ A
24+
25+
pattern ok v = inj₂ v
26+
pattern err e = inj₁ e
27+
28+
module _ where
29+
import Data.Sum.Categorical.Left (List ErrorPart) 0ℓ as S
30+
open import Category.Monad
31+
open RawMonad S.monad
32+
33+
failed-app : Term Arg Term Result Term
34+
failed-app t (arg _ a) = err (strErr "attempted to apply" ∷ termErr a ∷ strErr "to" ∷ termErr t ∷ [])
35+
36+
data Fuel : Set 0ℓ where
37+
fuel : Fuel
38+
39+
shift-index : Term Term
40+
shift-index-args : Args Term Args Term
41+
shift-index-clauses : List Clause List Clause
42+
43+
shift-index i j (var k args) with does (j ≤? k)
44+
... | true = var (i + k) $ shift-index-args i j args
45+
... | false = var k $ shift-index-args i j args
46+
shift-index i j (con c args) = con c $ shift-index-args i j args
47+
shift-index i j (def f args) = def f $ shift-index-args i j args
48+
shift-index i j (meta x args) = meta x $ shift-index-args i j args
49+
shift-index i j (lam v (abs s t)) = lam v $ abs s $ shift-index i (suc j) t
50+
shift-index i j (pat-lam cs args) = let
51+
cs = shift-index-clauses i j cs
52+
args = shift-index-args i j args
53+
in pat-lam cs args
54+
shift-index i j (Π[ s ∶ arg v A ] t) = let
55+
A = shift-index i j A
56+
t = shift-index i (suc j) t
57+
in Π[ s ∶ arg v A ] t
58+
shift-index i j (sort s) = sort s
59+
shift-index i j (lit l) = lit l
60+
shift-index i j unknown = unknown
61+
62+
shift-index-args i j [] = []
63+
shift-index-args i j (arg info a ∷ as) = let
64+
a = shift-index i j a
65+
as = shift-index-args i j as
66+
in arg info a ∷ as
67+
68+
shift-index-clauses i j [] = []
69+
shift-index-clauses i j (clause ps t ∷ cs) = let
70+
t = shift-index i (j + pattern-args-size ps) t
71+
cs = shift-index-clauses i j cs
72+
in clause ps t ∷ cs
73+
shift-index-clauses i j (absurd-clause ps ∷ cs) =
74+
absurd-clause ps ∷ shift-index-clauses i j cs
75+
76+
app : ⦃ Fuel ⦄ Arg Term Term Result Term
77+
app-many : ⦃ Fuel ⦄ Args Term Term Result Term
78+
subst : ⦃ Fuel ⦄ Term Term Result Term
79+
subst-args : ⦃ Fuel ⦄ Term Args Term Result (Args Term)
80+
subst-clauses : ⦃ Fuel ⦄ Term List (Clause) Result (List Clause)
81+
82+
app a (var x args) = return $ var x (args ∷ʳ a)
83+
app a (con c args) = return $ con c (args ∷ʳ a)
84+
app a (def f args) = return $ def f (args ∷ʳ a)
85+
app a (meta x args) = return $ meta x (args ∷ʳ a)
86+
app a (pat-lam cs args) = return $ pat-lam cs (args ∷ʳ a)
87+
app a @ (arg (arg-info v₁ _) x)
88+
b @ (lam v₂ (abs _ t))
89+
with does (v₁ ≟ᵥ v₂)
90+
... | true = subst 0 x t
91+
... | false = failed-app b a
92+
app a @ (arg (arg-info v₁ _) x)
93+
b @ (Π[ _ ∶ arg (arg-info v₂ _) _ ] t)
94+
with does (v₁ ≟ᵥ v₂)
95+
... | true = subst 0 x t
96+
... | false = failed-app b a
97+
-- catch all
98+
app a t = failed-app t a
99+
100+
app-many [] t = return t
101+
app-many (a ∷ as) t = do
102+
ta app a t
103+
app-many as ta
104+
105+
subst i x (var j args) with compare i j
106+
... | less m k = do
107+
args subst-args i x args
108+
-- decrement j by one since λ was eliminated
109+
return $ var (m + k) args -- j ≡ suc (m + k)
110+
... | greater _ _ = do
111+
args subst-args i x args
112+
-- j refers to variable named inside eliminated λ
113+
return $ var j args
114+
subst ⦃ fuel (suc n) ⦄
115+
i x (var j args) | equal _ = do
116+
args subst-args ⦃ fuel (suc n) ⦄ i x args
117+
app-many ⦃ fuel n ⦄ args (shift-index i 0 x)
118+
subst ⦃ fuel zero ⦄
119+
i x (var j []) | equal _ = return x
120+
subst ⦃ fuel zero ⦄
121+
_ _ (var j (_ ∷ _)) | equal _ = err (strErr "evaluation limit reached" ∷ [])
122+
subst i x (con c args) = do
123+
args subst-args i x args
124+
return $ con c args
125+
subst i x (def f args) = do
126+
args subst-args i x args
127+
return $ def f args
128+
subst i x (lam v (abs s t)) = do
129+
t subst (suc i) x t
130+
return $ lam v (abs s t)
131+
subst i x (meta m args) = do
132+
args subst-args i x args
133+
return $ meta m args
134+
subst i x (sort s) = return $ sort s
135+
subst i x (lit l) = return $ lit l
136+
subst i x unknown = return unknown
137+
subst i x (pat-lam cs args) = do
138+
cs subst-clauses i x cs
139+
args subst-args i x args
140+
return $ pat-lam cs args
141+
subst i x (Π[ s ∶ arg v A ] t) = do
142+
A subst i x A
143+
t subst (suc i) x t
144+
return $ Π[ s ∶ arg v A ] t
145+
146+
subst-args i x [] = return []
147+
subst-args i x (arg v a ∷ as) = do
148+
a subst i x a
149+
as subst-args i x as
150+
return $ arg v a ∷ as
151+
152+
subst-clauses i x [] = return []
153+
subst-clauses i x (clause ps t ∷ cs) = do
154+
t subst (i + pattern-args-size ps) x t
155+
cs subst-clauses i x cs
156+
return $ clause ps t ∷ cs
157+
subst-clauses i x (absurd-clause ps ∷ cs) = do
158+
cs subst-clauses i x cs
159+
return $ absurd-clause ps ∷ cs
160+
161+
{- Apply an argument to a term. Fails if the recusion limit is reached or an
162+
attempt is made to apply an argument to non-function-like term.
163+
-}
164+
apply : Term Arg Term Result Term
165+
apply f x = app ⦃ fuel limit ⦄ x f
166+
167+
open import Relation.Binary.PropositionalEquality
168+
169+
open import Relation.Unary
170+
171+
{- Retrieve any trailing arguments in a term -}
172+
term-args : Term Maybe (Args Term)
173+
term-args (var _ args) = just args
174+
term-args (con _ args) = just args
175+
term-args (def _ args) = just args
176+
term-args (pat-lam _ args) = just args
177+
term-args (meta _ args) = just args
178+
term-args other = nothing
179+
180+
{- Like term-args, but contains only the visible arguments -}
181+
term-vis-args : Term Maybe (List Term)
182+
term-vis-args t = do
183+
args term-args t
184+
just $ Data.List.map (λ {(arg _ t) t}) $ filter is-vis args
185+
where
186+
open import Data.Maybe using (_>>=_)
187+
args = term-args t
188+
is-vis : Decidable ((λ {(arg (arg-info v _) _) v}) ⊢ (_≡ visible))
189+
is-vis (arg (arg-info v r) x) = v ≟ᵥ visible
190+
191+
{- Conveniently convert a Result into a TC -}
192+
Result→TC : {A : Set 0ℓ} Result A TC A
193+
Result→TC (err e) = typeError e
194+
Result→TC (ok v) = returnTC v

src/Reflection/Pattern.agda

+14
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ module Reflection.Pattern where
1111
open import Data.List.Base hiding (_++_)
1212
open import Data.List.Properties
1313
open import Data.Product
14+
open import Data.Nat.Base
1415
open import Data.String as String using (String; braces; parens; _++_; _<+>_)
1516
import Reflection.Literal as Literal
1617
import Reflection.Name as Name
@@ -98,3 +99,16 @@ absurd ≟ absurd = yes refl
9899

99100
[] ≟s (_ ∷ _) = no λ()
100101
(_ ∷ _) ≟s [] = no λ()
102+
103+
pattern-size : Pattern
104+
pattern-args-size : List (Arg Pattern)
105+
106+
pattern-size (Pattern.con _ ps) = pattern-args-size ps
107+
pattern-size Pattern.dot = 1
108+
pattern-size (Pattern.var _) = 1
109+
pattern-size (Pattern.lit _) = 0
110+
pattern-size (Pattern.proj _) = 0
111+
pattern-size Pattern.absurd = 0
112+
113+
pattern-args-size [] = 0
114+
pattern-args-size (arg _ p ∷ ps) = pattern-size p + pattern-args-size ps

0 commit comments

Comments
 (0)