@@ -29,31 +29,40 @@ make-copattern declare? def-name tm tp = do
2929
3030 -- Agda will insert implicits when defining copatterns even
3131 -- 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'.
4756 body ←
4857 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))
5059
5160 -- Construct the final clause.
5261 pure $ clause clause-tele pat body
5362
5463 -- Define a copattern binding, and predeclare its type if required.
5564 case declare? of λ where
56- true → declare (argN def-name) tp
65+ true → declare (argN def-name) tp <|> pure tt
5766 false → pure tt
5867
5968 -- Construct the final copattern.
@@ -82,6 +91,17 @@ repack-record tm tp = do
8291 -- Builld a pointwise repacking.
8392 pure (tel→lam tele (con ctor args))
8493
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+
85105--------------------------------------------------------------------------------
86106-- Usage
87107
@@ -94,8 +114,10 @@ If you wish to give the binding a type annotation, you can also use
94114> copat : Your-type
95115> unquoteDecl copat = declare-copattern copat thing-to-be-expanded
96116
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.
99121
100122These macros also allow you to lift functions 'A → some-record-type'
101123into copattern definitions. Note that Agda will generate meta for
@@ -109,10 +131,13 @@ declare-copattern {A = A} nm x = do
109131 `A ← quoteTC A
110132 make-copattern true nm `x `A
111133
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
115139 `A ← quoteTC A
140+ `x ← define-abbrev nm "value" `A =<< quoteTC x
116141 make-copattern false nm `x `A
117142
118143{-
@@ -121,32 +146,19 @@ they cannot be quoted into any `Type ℓ`. With this in mind,
121146we also provide a pair of macros that work over `Typeω` instead.
122147-}
123148
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
139151 `A ← quoteωTC A
140152 -- Cannot quote things in type Typeω, but we can infer their type.
141153 `U ← infer-type `A
142154 make-copattern true nm `A `U
143155
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ω}
146158 → U → TC ⊤
147- define-copattern-levels nm A = do
148- `A ← quoteωTC A
159+ define-copatternω nm A = do
149160 `U ← get-type nm
161+ `A ← define-abbrev nm "value" `U =<< quoteωTC A
150162 make-copattern false nm `A `U
151163
152164{-
@@ -206,7 +218,11 @@ private module Test where
206218 zero-unused-param = record { actual = 0 }
207219
208220 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.
210226
211227 -- Functions into records that are universe polymorphic
212228 neat : ∀ {ℓ} {A : Type ℓ} → A → Record A
@@ -217,11 +233,11 @@ private module Test where
217233 -- Implicit insertion is correct for the define- macro, since the type
218234 -- of the function is given.
219235 cool : ∀ {ℓ} {A : Type ℓ} → A → Record A
220- unquoteDef cool = define-copattern-levels cool neat
236+ unquoteDef cool = define-copatternω cool neat
221237
222238 -- Eta-expanders
223239 expander : ∀ {m n : Nat} → Unused m → Unused n
224240 unquoteDef expander = define-eta-expansion expander
225241
226242 -- 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