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

Add Defer.recursiveFn to aid in recursion #4656

Merged
merged 2 commits into from
Sep 25, 2024

Conversation

johnynek
Copy link
Contributor

It took me a bit of thinking to implement this, so I think it could be of use. This simplifies writing a recursive function over a Defer[F] instance. This is particularly useful with monad transformers that give you Defer instances, e.g. EitherT[IO, MyError, A]

*/
def recursiveFn[A, B](fn: (A => F[B]) => (A => F[B])): A => F[B] =
new Function1[A, F[B]] { self =>
lazy val loopFn: A => F[B] = fn(self)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

we make this a lazy val so it is only evaluated once but only inside the defer below so we want until the first time it is actually need.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

but now that I write that down, I can't see a reason why you would need this. You should only apply self inside the recursion, but that means only when loopFn is called, which we don't do until we return the value, so it should be safe.

@satorg
Copy link
Contributor

satorg commented Sep 24, 2024

Interesting thought, thank you!
If I'm getting it correctly, recursiveFn looks like a generalization of fix in some way,
i.e. having fn: F[A] => F[A] we can probably assume that

fix(fn) <=> recursiveFn[Unit, A] { u2fa => Function.const[F[A], Unit](u2fa(())) }(())

Copy link
Contributor

@satorg satorg left a comment

Choose a reason for hiding this comment

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

Great, thanks!

@johnynek
Copy link
Contributor Author

I think your law is correct, but also hard to test. Most randomly generated random functions won't terminate I think (or at least many won't). So I don't know if we can actually make that test.

@johnynek johnynek merged commit 5fc8ede into main Sep 25, 2024
33 checks passed
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.

2 participants