Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document the meaning of pattern without no-eta-equality #6066

Closed
JasonGross opened this issue Aug 31, 2022 · 10 comments · Fixed by #6160
Closed

Document the meaning of pattern without no-eta-equality #6066

JasonGross opened this issue Aug 31, 2022 · 10 comments · Fixed by #6160
Assignees
Labels
eta η-expansion of metavariables and unification modulo η record constructors Issues involving record constructors. ux: documentation Issues relating to Agda's documentation ux: warnings Issues relating to the reporting of warnings
Milestone

Comments

@JasonGross
Copy link
Contributor

The documentation at https://agda.readthedocs.io/en/v2.6.2.2/language/record-types.html?highlight=pattern#recursive-records says:

However, inductive records without η-equality do not support both matching on the record constructor and construction of record elements by copattern matching. It has been discovered that the combination of both leads to loss of subject reduction, i.e., reduction does not preserve typing. For records without η, matching on the record constructor is off by default and construction by copattern matching is on. If you want the converse, you can add the record directive pattern:

As far as I can tell, the documentation does not specify what pattern does when either (or both) of the directives inductive, no-eta-equality are absent, despite the fact that Agda accepts it. I expect this is a no-op (is it?), but I think in any case the behavior should be documented.

@nad
Copy link
Contributor

nad commented Aug 31, 2022

Perhaps Agda could warn about certain combinations.

@andreasabel andreasabel added ux: documentation Issues relating to Agda's documentation record constructors Issues involving record constructors. labels Aug 31, 2022
@andreasabel andreasabel added this to the 2.6.3 milestone Sep 1, 2022
@andreasabel
Copy link
Member

If you explicitly declare eta-equality, you get a warning for pattern:

record D : Set1 where
  eta-equality; pattern; constructor d
  field
    foo : Set
`pattern' attribute ignored for eta record

However, if eta is inferred for the record, you do not get this warning:

record D : Set1 where
  pattern; constructor d
  field
    foo : Set

match : D  Set
match (d A) = A

comatch : Set  D
comatch A .D.foo = A

I suppose we could throw this warning also in the type-checker, after inferring eta-equality for a record type.

@andreasabel andreasabel self-assigned this Sep 30, 2022
@andreasabel
Copy link
Member

andreasabel commented Sep 30, 2022

The warning can be thrown when we turn on eta for a record after positivity checking:

-- | Turn on eta for inductive guarded recursive records.
-- Projections do not preserve guardedness.
recursiveRecord :: QName -> TCM ()
recursiveRecord q = do
ok <- etaEnabled
modifySignature $ updateDefinition q $ updateTheDef $ \case
r@Record{ recInduction = ind, recEtaEquality' = eta } ->
r { recEtaEquality' = eta' }
where
eta' | ok, Inferred NoEta{} <- eta, ind /= Just CoInductive = Inferred YesEta
| otherwise = eta
_ -> __IMPOSSIBLE__

-- | Turn on eta for non-recursive record, unless user declared otherwise.
nonRecursiveRecord :: QName -> TCM ()
nonRecursiveRecord q = whenM etaEnabled $ do
-- Do nothing if eta is disabled by option.
modifySignature $ updateDefinition q $ updateTheDef $ \case
r@Record{ recInduction = ind, recEtaEquality' = Inferred (NoEta _) }
| ind /= Just CoInductive ->
r { recEtaEquality' = Inferred YesEta }
r@Record{} -> r
_ -> __IMPOSSIBLE__

If my eyes do not deceive me, these two functions do exactly the same!?

They used to be different until e7240e8.

@andreasabel andreasabel added the ux: warnings Issues relating to the reporting of warnings label Sep 30, 2022
andreasabel added a commit that referenced this issue Sep 30, 2022
The warning "useless pattern directive" is now extended to records
with inferred eta (was only for declared eta).

However, to make it correct, we have to remember whether the record
constructor was subject to matching before we inferred eta for the
record.
(Note: the positivity checker runs at the end of the mutual block.)

I wonder whether we should rather advice the user to change `pattern`
to `eta-equality` in this case.  This would also save us the
bookkeeping of record constructor matches.
@andreasabel
Copy link
Member

Ok, there are cases when pattern is needed for records that are later recognized as eta-worthy:

mutual -- needed to trigger issue
record R : Set where -- needs to be in mutual block
pattern; constructor wrap
field f : Unit
G : R Set
G (wrap _) = Unit -- match on wrap needed

This record is classified by Agda as non-recursive.
So we have to keep track of whether pattern has been put to use.

@andreasabel
Copy link
Member

andreasabel commented Sep 30, 2022

I am in the process (#6154) of making Agda warn of a redundant pattern directive even when eta for a record is not declared, but inferred. In the case of Issue2308.agda (see above), it is not redundant since eta is inferred to late.

@JasonGross @nad @jespercockx @gallais @UlfNorell : Would you want Agda to recommend to replace pattern by eta-equality in cases like Issue2308.agda where eta is inferred, but too late to enable the match in G? The directive pattern correctly enables pattern matching on the record in the mutual block, but it might also wrongly suggest to the reader that copattern matching isn't available for R---yet which is, after the mutual block when eta has been established.

@andreasabel andreasabel added the eta η-expansion of metavariables and unification modulo η label Sep 30, 2022
@nad
Copy link
Contributor

nad commented Oct 3, 2022

I think that the user should declare whether η-equality should hold or not (via the absence or presence of a keyword), I don't think this property should be inferred by Agda.

@jespercockx
Copy link
Member

jespercockx commented Oct 3, 2022

"Inferred" is perhaps a strong word here, but I would be fine with there being a simple syntactic rule for when a record has eta-equality. For example, a record has eta-equality unless it has any of the keywords inductive, coinductive, pattern, or no-eta-equality. This is the nicest solution that I can think of that does not break basically all existing Agda code. (If I did not care about breaking existing code at all, I would propose making no-eta-equality the default and only enabling eta when the user requests it explicitly with the eta-equality keyword).

andreasabel added a commit that referenced this issue Oct 5, 2022
The new implementation separates the query whether an update is
necessary from the update.  This has to access the signature twice,
but skips the update if not needed---rather performing the identity
update which produces some garbage that needs to be collected.
@andreasabel
Copy link
Member

@nad and @jespercockx : Thanks for your opinions. I agree that it would be clearer if eta was not inferred, but declared. I second Jesper's proposal, with some modification:

  • no directive and inductive default to eta-equality
  • coinductive and pattern default to no-eta-equality
  • option --(no-)eta-equality is removed (this might break some code but it is easily fixable)
  • if eta-equality is not given explicitly but inferred unsafe by the positivity checker, it is switched off with a warning; if it was given explicitly then it is kept with a similar warning unless --safe; with --safe, an error is raised
  • the pragmas ETA (unsafe) and NOETA are removed

The ETA pragma was kept to allow unsafe eta equality without warning (unless --safe). However, one can also suppress the warning by the usual warning mechanism.

andreasabel added a commit that referenced this issue Oct 6, 2022
The new implementation separates the query whether an update is
necessary from the update.  This has to access the signature twice,
but skips the update if not needed---rather performing the identity
update which produces some garbage that needs to be collected.
@nad
Copy link
Contributor

nad commented Oct 6, 2022

I don't think we should treat things as unsafe only because the type-checker might fail to terminate.

@andreasabel
Copy link
Member

I don't think we should treat things as unsafe only because the type-checker might fail to terminate.

If I understand Anton @csetzer correctly, eta for coinductive records also breaks subject reduction: https://www.cs.swan.ac.uk/~csetzer/articles/CMCS2018/bergerSetzerProceedingsCMCS18.pdf

@andreasabel andreasabel changed the title The meaning of pattern without no-eta-equality shoud be documented Document the meaning of pattern without no-eta-equality Oct 24, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
eta η-expansion of metavariables and unification modulo η record constructors Issues involving record constructors. ux: documentation Issues relating to Agda's documentation ux: warnings Issues relating to the reporting of warnings
Projects
None yet
4 participants