-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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 toRightAssociated to AndThen #3527
Conversation
also, @alexandru in this line:
which was introduced in the original PR: it seems that if you call Should we not change that method to test if the passed function is already an Is there something I'm missing as to why that's safe? If so, can we add a comment so future readers aren't confused? |
fn match { | ||
case Concat(Concat(a, b), c) => loop(a, b, c, false) | ||
case Concat(a, Concat(b, c)) => loop(a, b, c, false) | ||
case Concat(Single(_, _), Single(_, _)) | Single(_, _) => fn |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could potentially combine adjacent Single
if the sum of their stack depth is < fusionMaxStackDepth
? Such a case might have been hidden by a non-right associated construction.
Codecov Report
@@ Coverage Diff @@
## master #3527 +/- ##
==========================================
- Coverage 91.29% 91.26% -0.03%
==========================================
Files 386 386
Lines 8577 8587 +10
Branches 240 235 -5
==========================================
+ Hits 7830 7837 +7
- Misses 747 750 +3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me. I definitely don't think AndThen
should maintain a lazy val with the right-associated instance, since if users want that it's easy enough for them to do it manually.
merged with HEAD, can you take a look @travisbrown |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 from me.
For use cases such as Scalding or fs2 or similar systems where you will build up an AST then run a lot of data through it, we will evaluate map functions many times.
AndThen is a good tool for stack safety, but it does the right-association as it evaluates and does not save work between calls. For monads such as IO, this is good, because in general the map function will be called at most once.
Also, the perf hit is mitigated by the fact that AndThen uses a 128 normal function calls before moving to a trampoline approach, so the graph of AndThen should be pretty shallow in the general case.
This PR adds a toRightAssociated method to convert an AndThen once to the right associated form, where the evaluation will only hit
Single(_, _)
orConcat(Single(_, _), _)
. This is impossible to do in an external function because Single and Concat are private.There is one open question: should
AndThen
keep alazy val
of the right associated version and routedef apply
through it? This could be a performance win for anyone that call an AndThen more than once I think, but at the expense that everyone takes a size hit of keeping both representations in memory.For now, we take the conservative approach of not changing anything but opening the API for use cases that know they will execute the function many times.