agda-stdlib icon indicating copy to clipboard operation
agda-stdlib copied to clipboard

Reasoning Combinators for Congruence?

Open Ailrun opened this issue 2 months ago • 14 comments

In a reasoning like the following:

begin type1 ≈⟨ equiv1 ⟩
      type2 ≈⟨ equiv2 ⟩
      structure type3 ≈⟨ congruence_for_structure equiv3 ⟩
      structure type4 ≈⟨ congruence_for_structure equiv4 ⟩
      structure type5 ≈⟨ congruence_for_structure equiv5 ⟩
      structure type6 ≈⟨ equiv6 ⟩
      type7 ≈⟨ equiv7 ⟩
      type8 ∎

i.e., a reasoning with multiple consecutive steps using a congruence, it is tedious to repeat the congruence. This is especially more burdensome if the congruence is fairly long. One can try to resolve this using a nested reasoning like

begin type1 ≈⟨ equiv1 ⟩
      type2 ≈⟨ equiv2 ⟩
      structure type3 ≈⟨ congruence_for_structure
        (begin type3 ≈⟨ equiv3 ⟩
               type4 ≈⟨ equiv4 ⟩
               type5 ≈⟨ equiv5 ⟩
               type6 ∎) ⟩
      structure type6 ≈⟨ equiv6 ⟩
      type7 ≈⟨ equiv7 ⟩
      type8 ∎

However, note that we need to repeat type3 and type6 twice. If they are also long/complex, this option does not help much either. It would be nice if there is some combinators with-cong⟨_⟩_ and _after-cong⟨_⟩_ (there would be better names, but for sake of giving the next example) that allows us to write the following:

begin type1 ≈⟨ equiv1 ⟩
      type2 ≈⟨ equiv2 ⟩
      with-cong⟨ congruence_for_structure ⟩
        type3 ≈⟨ equiv3 ⟩
        type4 ≈⟨ equiv4 ⟩
        type5 ≈⟨ equiv5 ⟩
        type6
      after-cong⟨ equiv6 ⟩
      type7 ≈⟨ equiv7 ⟩
      type8 ∎

or depending on the relation, even better:

begin type1 ≈⟨ equiv1 ⟩
      type2 ≈⟨ equiv2 ⟩
      with-cong⟨ structure ⟩
        type3 ≈⟨ equiv3 ⟩
        type4 ≈⟨ equiv4 ⟩
        type5 ≈⟨ equiv5 ⟩
        type6
      after-cong⟨ equiv6 ⟩
      type7 ≈⟨ equiv7 ⟩
      type8 ∎

Ailrun avatar Nov 06 '25 04:11 Ailrun

Should after-cong⟨ equiv ⟩ be a distinct step,... or a continuation as part of your hypothetical with-cong⟨_⟩ notation? Ie. something like

begin type1 ≈⟨ equiv1 ⟩
      type2 ≈⟨ equiv2 ⟩
      with-cong⟨ congruence_for_structure ⟩then⟨ equiv6 ⟩
        type3 ≈⟨ equiv3 ⟩
        type4 ≈⟨ equiv4 ⟩
        type5 ≈⟨ equiv5 ⟩
        type6
      type7 ≈⟨ equiv7 ⟩
      type8 ∎

jamesmckinna avatar Nov 06 '25 09:11 jamesmckinna

@jamesmckinna Thanks for the suggestion. I proposed _after-cong⟨_⟩_ as a separate step so that the order of equivalences stays the same. However, if this approach seems too verbose, what you suggested seems a good approach as well.

Ailrun avatar Nov 06 '25 15:11 Ailrun

So as the author of much of the current reasoning-based code, this is going to be quite complicated to implement and I think there are better ways to do it.

Firstly, have you seen the cong! tactic? I feel that if its only a few lines then cong! should suffice.

If the sub-reasoning has many lines then you really should be splitting out the sub-equality into a where block or even a different proof.

MatthewDaggitt avatar Nov 07 '25 05:11 MatthewDaggitt

Thanks @MatthewDaggitt ! Good to have the balance between expertise and enthusiasm when it comes to suggestions for new functionality.

jamesmckinna avatar Nov 07 '25 05:11 jamesmckinna

@MatthewDaggitt Thank you for the valuable comment! That tactic seems indeed very useful. However, I want to argue that the reasoning step I suggest is still useful separately. The tactic supports only equalities, not other equivalences, so we still have the problem in general case.

Ailrun avatar Nov 07 '25 05:11 Ailrun

Yes, that is a fair point. However, I think it's still clearer and more modular to split reasonable to split these subequalities out into a where block. Is there a problem with that approach?

MatthewDaggitt avatar Nov 07 '25 06:11 MatthewDaggitt

That approach shares the issue in the second approach of the original post, i.e. one needs to duplicate the initial and final types. If they are fairly complex, extracting a sub reasoning into a separate definition does not save much time/(textual) proof size.

Ailrun avatar Nov 07 '25 07:11 Ailrun

Hmmm, thinking about this a bit more: if type3 and type6 are duplicated and/or sufficiently complicated (whatever that may mean in any context), then I'd be tempted to abstract those out as named subterms in a where block as well... in support of @MatthewDaggitt 's thesis...

jamesmckinna avatar Nov 07 '25 09:11 jamesmckinna

Sure, that works. It is just more cumbersome in my opinion. I think the question is really how difficult to implement a combinator like this.

Ailrun avatar Nov 07 '25 15:11 Ailrun

Okay so:

begin type1 ≈⟨ equiv1 ⟩
      type2 ≈⟨ equiv2 ⟩
      with-cong⟨ congruence_for_structure ⟩
        type3 ≈⟨ equiv3 ⟩
        type4 ≈⟨ equiv4 ⟩
        type5 ≈⟨ equiv5 ⟩
        type6
      after-cong⟨ equiv6 ⟩
      type7 ≈⟨ equiv7 ⟩
      type8 ∎

vs

begin 
  type1           ≈⟨ equiv1 ⟩
  type2           ≈⟨ equiv2 ⟩
  structure type3 ≈⟨ cong structure equiv ⟩
  structure type6 ≈⟨ equiv6 ⟩
  type7           ≈⟨ equiv7 ⟩
  type8           ∎
  where
  equiv = begin
     type3 ≈⟨ equiv3 ⟩
     type4 ≈⟨ equiv4 ⟩
     type5 ≈⟨ equiv5 ⟩
     type6 ∎

I agree that your syntax is a little bit shorter, but however it does break the crucial point of the reasoning combinators, namely that they make all the intermediate types available at each step of the reasoning. Currently even though the intermediate types structure type3 and structure type6 are crucial to the proof, in your syntax they don't explicitly appear anywhere? In fact structure doesn't appear anywhere...

I feel this is a downgrade in readability of the proof no?

MatthewDaggitt avatar Nov 08 '25 03:11 MatthewDaggitt

Hm, that's a fair point. However, I think that can be adjusted in the combinator, e.g. so that it explicitly mentioned structure type3 before the combinator and skipping type3 or just to mention structure before.

Ailrun avatar Nov 08 '25 19:11 Ailrun

What would your proposed syntax be?

MatthewDaggitt avatar Nov 10 '25 00:11 MatthewDaggitt

How about the following syntax?

begin type1 ≈⟨ equiv1 ⟩
      type2 ≈⟨ equiv2 ⟩
      structure type3 under⟨ cong structure ⟩≈⟨ equiv3 ⟩
                type4 ≈⟨ equiv4 ⟩
                type5 ≈⟨ equiv5 ⟩then
      structure type6 ≈⟨ equiv6 ⟩
      type7 ≈⟨ equiv7 ⟩
      type8 ∎
  • Advantage: keeping the structure at the beginning and the end so that each step is clearly shown
  • Disadvantage: the beginning type of equiv3 and the ending type of equiv5 are less clear

Ailrun avatar Nov 11 '25 02:11 Ailrun

Minor: I personally prefer to put the begin on the line above, to use less horizontal space. But that's pure style.

As to the syntax, an alternate suggestion would be

begin type1 ≈⟨ equiv1 ⟩
           type2 ≈⟨ equiv2 ⟩
           structure type3 ≈cong[ structure ]⟨ equiv3 ⟩
                type4 ≈⟨ equiv4 ⟩
                type5 ≈⟨ equiv5 ⟩∎
      structure type6 ≈⟨ equiv6 ⟩
      type7 ≈⟨ equiv7 ⟩
      type8 ∎

JacquesCarette avatar Nov 11 '25 23:11 JacquesCarette