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

feat: remove Decidable instances from GetElem #4560

Merged
merged 10 commits into from
Jun 27, 2024
Merged

feat: remove Decidable instances from GetElem #4560

merged 10 commits into from
Jun 27, 2024

Conversation

kim-em
Copy link
Collaborator

@kim-em kim-em commented Jun 25, 2024

No description provided.

@kim-em kim-em added the WIP This is work in progress, and only a PR for the sake of CI or sharing. No review yet. label Jun 25, 2024
@kim-em kim-em requested a review from TwoFX June 25, 2024 11:41
@github-actions github-actions bot temporarily deployed to lean-lang.org/lean4/doc June 25, 2024 11:46 Inactive
@github-actions github-actions bot added the toolchain-available A toolchain is available for this PR, at leanprover/lean4-pr-releases:pr-release-NNNN label Jun 25, 2024
leanprover-community-mathlib4-bot added a commit to leanprover-community/batteries that referenced this pull request Jun 25, 2024
leanprover-community-mathlib4-bot added a commit to leanprover-community/mathlib4 that referenced this pull request Jun 25, 2024
@@ -222,6 +222,8 @@ def insertIfNew (m : HashMap α β) (a : α) (b : β) : HashMap α β × Option

instance : GetElem (HashMap α β) α (Option β) fun _ _ => True where
getElem m k _ := m.find? k
getElem? m k := some (m.find? k) -- Not really sure what should go here. We're meant to be returning an `Option (Option β)`.
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't this a sign that the instance doesn't quite make sense here? I'd expect there to be an Elem predicate, and that the result of getElem would not be an Option.

Copy link
Contributor

Choose a reason for hiding this comment

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

(I get the pragmatic reason why we don't have that right now, of course)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, @TwoFX will replace this with something more sensible in the big HashMap refactor.

@leanprover-community-mathlib4-bot leanprover-community-mathlib4-bot added breaks-mathlib This is not necessarily a blocker for merging: but there needs to be a plan release-ci Enable all CI checks for a PR, like is done for releases labels Jun 25, 2024
@leanprover-community-mathlib4-bot
Copy link
Collaborator

leanprover-community-mathlib4-bot commented Jun 25, 2024

Mathlib CI status (docs):

leanprover-community-mathlib4-bot added a commit to leanprover-community/batteries that referenced this pull request Jun 25, 2024
leanprover-community-mathlib4-bot added a commit to leanprover-community/mathlib4 that referenced this pull request Jun 25, 2024
@david-christiansen
Copy link
Contributor

Unfortunately, it doesn't seem to let me leave suggestions for lines that weren't changed. But here's a suggestion for an updated docstring to match the code better:

The class `GetElem coll idx elem valid` implements lookup notation,
specifically `xs[i]`, `xs[i]?`, `xs[i]!`, and `xs[i]'p`.

The types `coll`, `idx`, and `elem` are the collection, the index, and the
element types. A single collection may support lookups with multiple index
types. The relation `valid` determines when the index is guaranteed to be
valid; lookups of valid indices are guaranteed not to fail.

For example, an instance for arrays looks like
`GetElem (Array α) Nat α (fun xs i => i < xs.size)`. In other words, given an
array `xs` and a natural number `i`, `xs[i]` will return an `α` when `valid xs i`
holds, which is true when `i` is less than the size of the array. `Array`
additionally supports indexing with `USize`. Because the bounds are
checked at compile time, no runtime check is required.

Given `xs[i]` with `xs : coll` and `i : idx`, Lean looks for an instance of
`GetElem coll idx elem valid` and uses this to infer the type of the return
value `elem` and side conditions `valid` required to ensure `xs[i]` yields
a valid value of type `elem`. The tactic `get_elem_tactic` is
invoked to prove validity automatically. The `xs[i]'p` notation uses the
proof `p` to satisfy the validity condition, but it is often easier to place the
proof in the context using `have`, because `get_elem_tactic` tries
`assumption`.

`xs[i]?` and `xs[i]!` do not impose a proof obligation; the former returns
an `Option elem`, with `none` signalling that the value isn't present, and
the latter returns `elem` but panics if the value isn't there, returning
`default : elem` based on the `Inhabited elem` instance.

The proof side-condition `valid xs i` is automatically dispatched by the
`get_elem_tactic` tactic; this tactic can be extended by adding more clauses to
`get_elem_tactic_trivial` using `macro_rules`.

Important instances include:
  * `arr[i] : α` where `arr : Array α` and `i : Nat` or `i : USize`: does array
    indexing with no bounds check and a proof side goal `i < arr.size`.
  * `l[i] : α` where `l : List α` and `i : Nat`: index into a list, with proof
    side goal `i < l.length`.
  * `stx[i] : Syntax` where `stx : Syntax` and `i : Nat`: get a syntax argument,
    no side goal (returns `.missing` out of range)

-/
class GetElem (coll : Type u) (idx : Type v) (elem : outParam (Type w))
              (valid : outParam (coll → idx → Prop)) where
  /--
  The syntax `arr[i]` gets the `i`'th element of the collection `arr`. If there
  are proof side conditions to the application, they will be automatically
  inferred by the `get_elem_tactic` tactic.
  -/

What do you think?

@nomeata
Copy link
Collaborator

nomeata commented Jun 25, 2024

Good! Should we exclude Syntax from the docstring? The docstring is most useful to relative beginners of Lean, and I expect they are confused or at least distracted by meta-programming concepts. We can hopefully add HashMap instead soon!

@david-christiansen
Copy link
Contributor

I agree!

@kim-em
Copy link
Collaborator Author

kim-em commented Jun 25, 2024

Thanks, I've adopted the doc-string, with a few minor changes.

@github-actions github-actions bot temporarily deployed to lean-lang.org/lean4/doc June 25, 2024 23:31 Inactive
leanprover-community-mathlib4-bot added a commit to leanprover-community/batteries that referenced this pull request Jun 26, 2024
leanprover-community-mathlib4-bot added a commit to leanprover-community/mathlib4 that referenced this pull request Jun 26, 2024
@leanprover-community-mathlib4-bot leanprover-community-mathlib4-bot added builds-mathlib CI has verified that Mathlib builds against this PR and removed breaks-mathlib This is not necessarily a blocker for merging: but there needs to be a plan labels Jun 26, 2024
@kim-em
Copy link
Collaborator Author

kim-em commented Jun 26, 2024

An outstanding issue here is that we no longer provide default implementations of getElem? and getElem!, adding to the implementation burden when creating GetElem instances.

@TwoFX wrote elsewhere:

It would be really cool if we could provide the class as

class GetElem (coll : Type u) (idx : Type v) (elem : outParam (Type w))
              (valid : outParam (coll → idx → Prop)) where
  getElem (xs : coll) (i : idx) (h : valid xs i) : elem

  getElem? : coll → idx → Option elem := by
    exact fun xs i => if h : _ then some (getElem xs i h) else none

  getElem! [Inhabited elem] (xs : coll) (i : idx) : elem :=
    match getElem? xs i with | some e => e | none => outOfBounds

with the intention to defer elaboration until a user provides an instance that omits getElem? so that the elaborator can figure out the correct decidable instance at that time. This almost works, the only problem is that in the tactic block for getElem? the elaborator takes getElem to mean GetElem.getElem instead of the getElem above and then fails to synthesize the very instance we're currently defining. Can we fix this?

I propose that we merge as is for now, but keep thinking if there's a clever trick here.

Getting these Decidable instances out of the lookup functions is a big win.

@kim-em kim-em added awaiting-review Waiting for someone to review the PR and removed WIP This is work in progress, and only a PR for the sake of CI or sharing. No review yet. labels Jun 26, 2024
@kim-em kim-em requested a review from digama0 as a code owner June 26, 2024 03:15
@github-actions github-actions bot temporarily deployed to lean-lang.org/lean4/doc June 26, 2024 04:03 Inactive
@github-actions github-actions bot temporarily deployed to lean-lang.org/lean4/doc June 26, 2024 04:45 Inactive
leanprover-community-mathlib4-bot added a commit to leanprover-community/batteries that referenced this pull request Jun 26, 2024
leanprover-community-mathlib4-bot added a commit to leanprover-community/mathlib4 that referenced this pull request Jun 26, 2024
Copy link
Member

@tydeu tydeu left a comment

Choose a reason for hiding this comment

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

Below are a few GetElem instances that can be removed because of getElemOfDecidable which I imagine just slipped through.

@kim-em
Copy link
Collaborator Author

kim-em commented Jun 26, 2024

Below are a few GetElem instances that can be removed because of getElemOfDecidable which I imagine just slipped through.

The rename had already happened, so these are actually the ones that are needed!

@github-actions github-actions bot temporarily deployed to lean-lang.org/lean4/doc June 26, 2024 06:43 Inactive
leanprover-community-mathlib4-bot added a commit to leanprover-community/batteries that referenced this pull request Jun 26, 2024
leanprover-community-mathlib4-bot added a commit to leanprover-community/mathlib4 that referenced this pull request Jun 26, 2024
@leanprover-community-mathlib4-bot leanprover-community-mathlib4-bot added breaks-mathlib This is not necessarily a blocker for merging: but there needs to be a plan and removed builds-mathlib CI has verified that Mathlib builds against this PR labels Jun 26, 2024
Copy link
Member

@TwoFX TwoFX left a comment

Choose a reason for hiding this comment

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

LGTM!

Copy link
Member

@tydeu tydeu left a comment

Choose a reason for hiding this comment

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

Looks great to me as well!

@kim-em kim-em removed the awaiting-review Waiting for someone to review the PR label Jun 27, 2024
@kim-em kim-em added this pull request to the merge queue Jun 27, 2024
Merged via the queue into master with commit 5c978a2 Jun 27, 2024
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaks-mathlib This is not necessarily a blocker for merging: but there needs to be a plan release-ci Enable all CI checks for a PR, like is done for releases toolchain-available A toolchain is available for this PR, at leanprover/lean4-pr-releases:pr-release-NNNN
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants