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 bind alias for Sequence operation in DSL #2978

Merged
merged 12 commits into from
Mar 24, 2023
Merged

Add bind alias for Sequence operation in DSL #2978

merged 12 commits into from
Mar 24, 2023

Conversation

nomisRev
Copy link
Member

Adds bind as suggested by @pakoito in #2861.
Updates sequence deprecation to point towards DSL.

@nomisRev nomisRev requested review from serras and pakoito March 13, 2023 16:34
@serras
Copy link
Member

serras commented Mar 15, 2023

I'm not a fan of reusing the bind name for both Iterable and non-Iterable versions.

@nomisRev
Copy link
Member Author

I'm not a fan of reusing the bind name for both Iterable and non-Iterable versions.

I named it bind simply because it didn't have a conflict (in signature) with the other bind 😅
If you like the API, but dislike the name we can also rename it. @pakoito originally proposed bindAll.

@serras
Copy link
Member

serras commented Mar 15, 2023

I'm not a fan of reusing the bind name for both Iterable and non-Iterable versions.

I named it bind simply because it didn't have a conflict (in signature) with the other bind 😅 If you like the API, but dislike the name we can also rename it. @pakoito originally proposed bindAll.

I would prefer that name, indeed.

@nomisRev
Copy link
Member Author

@serras one follow-up question, for RaiseAccumulate this should be overwritten and use accumulate strategy for bindAll, right?

@serras
Copy link
Member

serras commented Mar 15, 2023

@serras one follow-up question, for RaiseAccumulate this should be overwritten and use accumulate strategy for bindAll, right?

That would be great! I thought that merely calling bind inside RaiseAccumulate would be enough to have this behavior, but if we need to overload bindAll there too, I would make the change too.

@nomisRev
Copy link
Member Author

nomisRev commented Mar 15, 2023

Calling bind within the lambda still short_circuits the "current op".

I.e.

listOf(1, 2).mapOrAccumulate {
  if(it == 1) {
     "fail-1".left().bind() // <-- short-circuits "current op"
     "fail-1".left().bind() // this is not accumulated
  } else {
    listOf("fail-2".left(), "fail-2".left()).bindAll() // both get accumulated
  }
} // Either.Left(NonEmptyList("fail-1", "fail-2", "fail-2"))

So bindAll needs to have a specialised implementation since map { it.bind() } would result in the 1 scenario. Or am I overlooking something?

@serras
Copy link
Member

serras commented Mar 15, 2023

@nomisRev It makes sense to me, that due to the way types are resolved the bind() gets called on Raise<E> instead of RaiseAccumulate<E>. It still needed a bit of additional thinking, though, it doesn't seem entirely obvious to me. So good point that we're adding it to RaiseAccumulate, because that's the least surprising behavior.

@nomisRev
Copy link
Member Author

@serras I am not sure I entirely follow your train of though.

It makes sense to me, that due to the way types are resolved the bind() gets called on Raise instead of RaiseAccumulate.

Isn't this irrelevant? There is no other way for bind to work? What would the semantics otherwise be? Since bind returns A it has to short-circuit, right? Otherwise it would have to return something like Value which you modelled in Accumulate DSL. & thus de-coupling the DSL completely from Raise.

It still needed a bit of additional thinking, though, it doesn't seem entirely obvious to me.

Not sure I understood this comment. Is it the short-circuit behavior inside of accumulate that requires additional thinking? Or the fact that semantics of bind remain the same and bindAll semantics change depending on being inside Raise or RaiseAccumulate?

@@ -615,6 +616,31 @@ class EffectSpec : StringSpec({
}
}

"bindAll fails on first error" {
Copy link
Member Author

Choose a reason for hiding this comment

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

Here are the two tests that show the behavior @serras

@arrow-kt arrow-kt deleted a comment from rafaparadela Mar 16, 2023
@nomisRev nomisRev marked this pull request as ready for review March 16, 2023 13:02
@nomisRev nomisRev added the 1.2.0 Tickets belonging to 1.1.2 label Mar 16, 2023
Copy link
Collaborator

@franciscodr franciscodr left a comment

Choose a reason for hiding this comment

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

Just a few typos. Thanks, @nomisRev!

public fun <A> Iterable<Option<A>>.sequence(): Option<List<A>> =
traverse(::identity)
let { l -> option { l.bindAll() } }
Copy link
Member

Choose a reason for hiding this comment

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

the let is unnecessary here, right?

Copy link
Member

Choose a reason for hiding this comment

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

option { this@sequence.bindAll() }

Copy link
Member Author

@nomisRev nomisRev Mar 23, 2023

Choose a reason for hiding this comment

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

Yes, indeed it's so that the ReplaceWith is inline with the implementation body if people click through. Without let ReplaceWith horribly suffers from scope pollution 😞

let should incur any perf penalty due to @InlineOnly.

@pakoito
Copy link
Member

pakoito commented Mar 23, 2023

I was wondering why I got a Mentioned notification :D Good to hear my suggestion made it <3

On the mini-arrow I made for TypeScript we have traverse for Either<E[], A[]>, traverseFailFast for Either<E, A[]> and traverseSeparate for a surprisingly useful Pair<E[], A[]>.

@nomisRev
Copy link
Member Author

nomisRev commented Mar 23, 2023

We have traverse separate but it’s called separateEither since we also have separateIor (and now deprecated separateValidated).

It’s indeed very useful, we’ve had it since before 1.0.0 though. Originally in Alternative typeclass, and then as extension on Iterable.

And ofc, your feedback and knowledge is always super valuable @pakoito ❤️ Miss you 😘

@serras serras merged commit 2c9489a into main Mar 24, 2023
@nomisRev nomisRev deleted the sv-bind-iterable branch March 24, 2023 08:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
1.2.0 Tickets belonging to 1.1.2
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants