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

replace trivial rcases with have #200

Merged
merged 1 commit into from
Jan 18, 2024
Merged

replace trivial rcases with have #200

merged 1 commit into from
Jan 18, 2024

Conversation

cdisselkoen
Copy link
Contributor

This PR is pure refactoring, no functional change.

Replaces (almost) all of our use of rcases with a trivial pattern (no destructuring, or just destructuring a conjunction) with an equivalent have.

Some side effects:

  • Affects case names subsequent to the replacement. This is a beneficial side effect; the new names are simpler but equally informative.
  • Some behavior is different when we use rcases/have to shadow a previous binding, as in have ⟨_, h₁⟩ := h₁. I believe the shadowed (but still present) binding is put in a different order by rcases vs have, which may affect any subsequent renaming operations. I've made the necessary adjustments in this PR; they are minor. In many of these cases I just removed the shadowing for clarity.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@cdisselkoen cdisselkoen requested review from emina and khieta January 18, 2024 17:30
rcases h₁ with ⟨hl₁, h₁⟩ ; subst hl₁
rcases h₂ with ⟨hl₂, h₂⟩ ; subst hl₂
rcases (Values.lt_trans h₁ h₂) with h₃
have ⟨hl₁, h₃⟩ := h₁ ; subst hl₁
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should use rcases in all cases that requires deconstructing the output, like this one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's your rationale?

Copy link
Contributor

@emina emina Jan 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think rcases looks better in this case, and it makes the code style more consistent.

We clearly can't replace rcases with have everywhere, because it's a more powerful tactic. So, I'd prefer a simple rule for when to use one versus the other: use rcases when you need to deconstruct, and use have otherwise.

Using rcases also makes it possible / easier to apply a more advanced deconstruction pattern if that becomes necessary in the future as proofs change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've thought about this more, and I propose a different simple rule for one versus the other: rcases for patterns involving |, and have in all other cases.

The reason I think this is sensible is that it reserves rcases for the times when we're actually splitting goals into separate cases, hence the name. When we destructure an and with ⟨_, _⟩, we're not casing on anything. Lean splits our goal into 1 subcase called "intro", which is not helpful or elegant.

I'm skeptical that we will often be refactoring in a way that changes a term from a non-| pattern to a | pattern or vice versa. And realistically, if we do need to refactor in that way, that will involve more invasive changes to the remainder of the proof (as we now have multiple cases to consider, or no longer have multiple cases to consider, respectively), so it's not a huge burden to change between rcases and have during that refactor.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I think have looks nicer than rcases for ⟨_, _⟩ expressions. The syntax looks sort of like a let, which makes it easier for me to remember.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, the rule works.

But I still find having the matching pattern on the LHS really counterintuitive. At least for all the languages I'm used to, the pattern-matching happens on the right.

I see why have is more appealing for binding a single name (a regular let). But for deconstruction,rcases still looks better to me because it reads as match.

Curious: is there any observable effect on proof performance (e.g., faster with have)?

Or we just have to settle this based on the aesthetics? 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CI took 2min 38sec to build the Lean for this PR, vs 2min 41sec to build the Lean in #199 (the previous change). Could be noise, or could be that have is a small improvement vs rcases. (I have to imagine that have is if anything faster, because since it is less powerful, it is doing less. It's also not creating new subgoals like rcases is, even for trivial matches.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I was hoping that have would be much faster (because it's doing less), so that would be a good justification to go with have even for those who find it less intuitive 🙂

I don't love it but I'll take the 3 seconds!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like just a matter of preference then 🤷‍♀️ I usually reach for let over match because it avoids the extra indentation. (Which is not applicable in this case -- that's just why I like let)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, just a matter of preference. And we have 2 vs 1 votes for pattern-matching on the left, so I'm disagreeing and committing on this one :)

Comment on lines -473 to +478
rcases h₂ with ⟨h₂, _⟩
rcases h₂ with ⟨hl₂, hr₂⟩ ; subst hl₂ hr₂
have ⟨⟨hl₂, hr₂⟩, _⟩ := h₂
subst hl₂ hr₂
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here's an example of compound deconstruction with have. (Replacing rcases code that wasn't even doing the compound deconstruction 😂 )

@cdisselkoen cdisselkoen merged commit c8b4c6d into main Jan 18, 2024
3 checks passed
@cdisselkoen cdisselkoen deleted the cdisselkoen/lean-have branch January 18, 2024 19:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants