-
Notifications
You must be signed in to change notification settings - Fork 453
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
Allow bindNel in mapOrAccumulate, and add missing signatures #2952
Conversation
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.
LGTM
I'm not sure what is the best intermediate solution until context receivers land. All feedback is very welcome, thoughts or ideas. And ask any and all questions if you have anything or the explanation in the description is not clear 🙏 |
The most important part in this migration is to make sure all old functions that will behave differently but compile fine are deprecated with explanations and/or ReplaceWiths. |
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.
I discussed some if this PR offline with Simon, thanks for the clarifications
The |
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.
I love this PR! (as much as you can love code, of course)
This PR adds missing signatures of
mapOrAccumulate
alongside https://github.com/arrow-kt/arrow/pull/2940/files & #2935.Our
mapOrAccumulate
was currently not compatible withEitherNel
(orValidatedNel
), and this adds some friction when accumulating errors. There are several solution to this problem:Redefine
mapOrAccumulateNel
overRaise<NonEmptyList<E>>
instead ofRaise<E>
and require callers to transform fromE
toNonEmptyList<E>
before callingbind
orraise
usingeither.toEitherNel()
ormapErrorNel { }
. This results in theValidated
deprecation to look like this fortraverse
:Introduce
mapOrAccumulateNel
, it needs to disambiguate in name or there is ambiguity in the API and the compiler cannot select the correct one based on@BuilderInference
. (Can follow similar source -and binary compatible way migration post context-receivers). Requires explicitly callingmapOrAccumulate
ormapOrAccumulateNel
, and still requires explicit transformation using usingeither.toEitherNel()
ormapErrorNel { }
in cases where you need to mix-and-match.Introduce
AccumulatingRaise
which simulates the below context receivers based code. The upside here is thatE
andNonEmptyList<E>
work seamlessly together, but the downside is that it introduces some minor issues with type interference, and in some cases the users will have to explicitly specify the type arguments. This is the case whenE
cannot be inferred by surrounding code,@BuilderInference
is partially broken in this case due to ambiguity betweenEither<E>.bind
andEitherNel<E>.bind
.Side-notes
Inference problems
If you call
bind
onValidated<E, _>
orEither<E, _>
then@BuilderInference
works, similarly forraise("test")
.Alternatively if you call
bind
orraise
onNonEmptyList<E>
then it causes disambiguity, and you need to disambiguate. Disambiguating by specifying a return type only works if you don't chain another function liketoValidated
ormap
, in those cases you need to explicitly specify the type arguments. Explicitly specifying the type arguments always solves the disambiguity problem.Future proofing
In option 2, and 3 we can migrate to context-receivers once they are released by marking
mapOrAccumulate
withAccumulatingRaise
as@Deprecation(DeprecationLevel.HIDDEN)
and introducing the above defined code. This will then be binary -and source compatible. All that would be needed is an additional import toarrow.core.raise.bind
, this can be easily automated withOpenRewrite
orReplaceWith
.