@@ -29,31 +29,40 @@ make-copattern declare? def-name tm tp = do
29
29
30
30
-- Agda will insert implicits when defining copatterns even
31
31
-- with 'withExpandLast true', so we need to do implicit instantiation
32
- -- by hand. First, we strip off all leading implicits from the field type.
33
- let (implicit-tele , tp) = pi-impl-view field-tp
34
- let nimplicits = length implicit-tele
35
- let clause-tele = tele ++ implicit-tele
36
-
37
- -- Construct the pattern portion of the clause, making sure to bind
38
- -- all implicit variables. Note that copattern projections are always visible.
39
- let pat =
40
- tel→pats nimplicits tele ++
41
- arg (set-visibility visible field-info) (proj field-name) ∷
42
- tel→pats 0 implicit-tele
43
-
44
- -- Construct the body of the clause, making sure to apply all arguments
45
- -- bound outside the copattern match, and instantiate all implicit arguments.
46
- -- We also need to apply all of the implicit arguments to 'tm'.
32
+ -- by hand. There are also cases where it's better to fully
33
+ -- eta-expand than not (e.g. the 'helper' we're expanding has a
34
+ -- field defined by lazy matching, which does not reduce unless
35
+ -- applied, and would cause duplication of the big input term). So
36
+ -- we fully eta-expand clauses here.
37
+ -- First, we strip off all leading quantifiers from the field
38
+ -- type.
39
+ let
40
+ (field-tele , tp) = pi-view field-tp
41
+ nargs = length field-tele
42
+ clause-tele = tele ++ field-tele
43
+
44
+ -- Construct the pattern portion of the clause, making sure to
45
+ -- bind all variables. Note that copattern projections are always
46
+ -- visible.
47
+ let
48
+ pat = tel→pats nargs tele ++
49
+ arg (set-visibility visible field-info) (proj field-name) ∷
50
+ tel→pats 0 field-tele
51
+
52
+ -- Construct the body of the clause, making sure to apply all
53
+ -- arguments bound outside the copattern match, and apply the
54
+ -- eta-expanded arguments. We also need to apply all of the
55
+ -- implicit arguments to 'tm'.
47
56
body ←
48
57
in-context (reverse clause-tele) $
49
- reduce (def field-name (argN ( raise nimplicits inst-tm) ∷ tel→args 0 implicit -tele))
58
+ reduce (def field-name (raise nargs inst-tm v ∷ tel→args 0 field -tele))
50
59
51
60
-- Construct the final clause.
52
61
pure $ clause clause-tele pat body
53
62
54
63
-- Define a copattern binding, and predeclare its type if required.
55
64
case declare? of λ where
56
- true → declare (argN def-name) tp
65
+ true → declare (argN def-name) tp <|> pure tt
57
66
false → pure tt
58
67
59
68
-- Construct the final copattern.
@@ -82,6 +91,17 @@ repack-record tm tp = do
82
91
-- Builld a pointwise repacking.
83
92
pure (tel→lam tele (con ctor args))
84
93
94
+ -- Helper for the 'define' macros; Unifies the given goal with the type
95
+ -- of the given function, if it has been defined. If the function has
96
+ -- not been defined, and the first argument is 'false', then an error is
97
+ -- raised.
98
+ type-for : String → Bool → Name → Term → TC ⊤
99
+ type-for tac decl? fun goal with decl?
100
+ ... | true = (unify goal =<< get-type fun) <|> pure tt
101
+ ... | false = (unify goal =<< get-type fun) <|> typeError
102
+ [ "define-" , strErr tac , ": the function " , nameErr fun , " should already have been declared."
103
+ ]
104
+
85
105
--------------------------------------------------------------------------------
86
106
-- Usage
87
107
@@ -94,8 +114,10 @@ If you wish to give the binding a type annotation, you can also use
94
114
> copat : Your-type
95
115
> unquoteDecl copat = declare-copattern copat thing-to-be-expanded
96
116
97
- All features of non-recursive records are supported, including instance
98
- fields and fields with implicit arguments.
117
+ Note that, in this case, the thing-to-be-expanded must have exactly the
118
+ same type as the binding `copat`. All features of non-recursive records
119
+ are supported, including instance fields and fields with implicit
120
+ arguments.
99
121
100
122
These macros also allow you to lift functions 'A → some-record-type'
101
123
into copattern definitions. Note that Agda will generate meta for
@@ -109,10 +131,13 @@ declare-copattern {A = A} nm x = do
109
131
`A ← quoteTC A
110
132
make-copattern true nm `x `A
111
133
112
- define-copattern : ∀ {ℓ} {A : Type ℓ} → Name → A → TC ⊤
113
- define-copattern {A = A} nm x = do
114
- `x ← quoteTC x
134
+ define-copattern
135
+ : ∀ {ℓ} (nm : Name)
136
+ → {@(tactic (type-for "copattern" true nm)) A : Type ℓ}
137
+ → A → TC ⊤
138
+ define-copattern nm {A = A} x = do
115
139
`A ← quoteTC A
140
+ `x ← define-abbrev nm "value" `A =<< quoteTC x
116
141
make-copattern false nm `x `A
117
142
118
143
{-
@@ -121,32 +146,19 @@ they cannot be quoted into any `Type ℓ`. With this in mind,
121
146
we also provide a pair of macros that work over `Typeω` instead.
122
147
-}
123
148
124
- -- Helper for the 'define' macros; Unifies the given goal with the type
125
- -- of the given function, if it has been defined. If the function has
126
- -- not been defined, and the first argument is 'false', then an error is
127
- -- raised.
128
- type-for : Bool → Name → Term → TC ⊤
129
- type-for decl? fun goal with decl?
130
- ... | true = (unify goal =<< get-type fun) <|> pure tt
131
- ... | false = (unify goal =<< get-type fun) <|> typeError
132
- [ "define-copattern-levels: the function " , nameErr fun , " should already have been declared."
133
- ]
134
-
135
- declare-copattern-levels
136
- : (nm : Name) {@(tactic (type-for true nm)) U : Typeω}
137
- → U → TC ⊤
138
- declare-copattern-levels nm A = do
149
+ declare-copatternω : ∀ {U : Typeω} → Name → U → TC ⊤
150
+ declare-copatternω nm A = do
139
151
`A ← quoteωTC A
140
152
-- Cannot quote things in type Typeω, but we can infer their type.
141
153
`U ← infer-type `A
142
154
make-copattern true nm `A `U
143
155
144
- define-copattern-levels
145
- : (nm : Name) {@(tactic (type-for false nm)) U : Typeω}
156
+ define-copatternω
157
+ : (nm : Name) {@(tactic (type-for "copatternω" false nm)) U : Typeω}
146
158
→ U → TC ⊤
147
- define-copattern-levels nm A = do
148
- `A ← quoteωTC A
159
+ define-copatternω nm A = do
149
160
`U ← get-type nm
161
+ `A ← define-abbrev nm "value" `U =<< quoteωTC A
150
162
make-copattern false nm `A `U
151
163
152
164
{-
@@ -206,7 +218,11 @@ private module Test where
206
218
zero-unused-param = record { actual = 0 }
207
219
208
220
one-unused-param : ∀ {n} → Unused n
209
- unquoteDef one-unused-param = define-copattern one-unused-param zero-unused-param
221
+ unquoteDef one-unused-param = declare-copattern one-unused-param zero-unused-param
222
+ -- This is a type error:
223
+ -- unquoteDef one-unused-param = define-copattern one-unused-param zero-unused-param
224
+ -- because the 'define' macro propagates the type of the thing being
225
+ -- defined inwards.
210
226
211
227
-- Functions into records that are universe polymorphic
212
228
neat : ∀ {ℓ} {A : Type ℓ} → A → Record A
@@ -217,11 +233,11 @@ private module Test where
217
233
-- Implicit insertion is correct for the define- macro, since the type
218
234
-- of the function is given.
219
235
cool : ∀ {ℓ} {A : Type ℓ} → A → Record A
220
- unquoteDef cool = define-copattern-levels cool neat
236
+ unquoteDef cool = define-copatternω cool neat
221
237
222
238
-- Eta-expanders
223
239
expander : ∀ {m n : Nat} → Unused m → Unused n
224
240
unquoteDef expander = define-eta-expansion expander
225
241
226
242
-- Raises a type error: the function should have a declaration.
227
- -- unquoteDecl uncool = define-copattern-levels uncool neat
243
+ -- unquoteDecl uncool = define-copatternω uncool neat
0 commit comments