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: tail-recursive and short-circuiting version of List.any/all #392

Closed
wants to merge 2 commits into from

Conversation

semorrison
Copy link
Collaborator

No description provided.

@semorrison semorrison added the awaiting-review This PR is ready for review; the author thinks it is ready to be merged. label Nov 26, 2023
Copy link
Collaborator

@fgdorais fgdorais 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! Just a couple rounds of golf...

Std/Data/List/Basic.lean Outdated Show resolved Hide resolved
Std/Data/List/Basic.lean Outdated Show resolved Hide resolved
Co-authored-by: François G. Dorais <fgdorais@gmail.com>
Comment on lines +17 to +24
def anyTR (xs : List α) (p : α → Bool) : Bool :=
go false xs
where
/-- Auxiliary for `anyTR`. -/
go : Bool → List α → Bool
| true, _ => true
| false, [] => false
| false, h :: t => go (p h) t
Copy link
Contributor

Choose a reason for hiding this comment

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

How about the following?

Suggested change
def anyTR (xs : List α) (p : α → Bool) : Bool :=
go false xs
where
/-- Auxiliary for `anyTR`. -/
go : Bool → List α → Bool
| true, _ => true
| false, [] => false
| false, h :: t => go (p h) t
def anyTR : List α -> (α → Bool) -> Bool
| [], _ => false
| h :: t, p => p h || anyTR t p

Copy link
Collaborator

Choose a reason for hiding this comment

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

Neat! That is indeed tail recursive! Makes me wonder if it's intentional that List.any in core is not short-circuiting?

Copy link
Collaborator

Choose a reason for hiding this comment

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

After inspecting the C code in stage0, it seems that List.or, which is the specialization of List.any where p=id, compiles as short-circuiting tail-recursive code. I'm not sure about List.any though since it has a lot more C crud.

I wonder if the short-circuiting tail-recursive version should actually be in core?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

💡 Interesting. I wish we had an annotation to require / check tail-recursiveness...

Copy link
Member

Choose a reason for hiding this comment

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

@fgdorais my tail recursion detector says that List.any/List.all is not tail-recursive, but List.or/List.and is, which is a bit mysterious.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm ok with merging anyTR/allTR if that would unblock something, but making the change to core seems preferable.

Comment on lines +32 to +39
def allTR (xs : List α) (p : α → Bool) : Bool :=
go true xs
where
/-- Auxiliary for `allTR`. -/
go : Bool → List α → Bool
| false, _ => false
| true, [] => true
| true, h :: t => go (p h) t
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
def allTR (xs : List α) (p : α → Bool) : Bool :=
go true xs
where
/-- Auxiliary for `allTR`. -/
go : Bool → List α → Bool
| false, _ => false
| true, [] => true
| true, h :: t => go (p h) t
def allTR : List α -> (α → Bool) -> Bool
| [], _ => true
| h :: t, p => p h && allTR t p

@semorrison
Copy link
Collaborator Author

I'll close this in favour of leanprover/lean4#2972. Reviews there welcome.

@semorrison semorrison closed this Nov 28, 2023
github-merge-queue bot pushed a commit to leanprover/lean4 that referenced this pull request Dec 11, 2023
Changes the implementation of `List.all` and `List.any` so they
short-circuit. The implementations are tail-recursive.

This replaces leanprover-community/batteries#392, which was
going to do this with `@[csimp]`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting-review This PR is ready for review; the author thinks it is ready to be merged.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants