Choice and Alternative traits refactor #1397
louthy
announced in
Announcements
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Two new traits have been added:
Choice<F>Choice<F>allows for propagation of 'failure' and 'choice' (in some appropriate sense, depending on the type).Choiceis aSemigroupK, but has aChoosemethod, rather than relying on theSemigroupK.Combinemethod, (which now has a default implementation of invokingChoose). That creates a new semantic meaning forChoose, which is about choice propagation rather than the broader meaning ofCombine. It also allows forChooseandCombineto have separate implementations depending on the type.The way to think about
Chooseand the inheritedSemigroupK.Combinemethods is:Chooseis the failure/choice propagation operator:|Combineis the concatenation/combination/addition operator:+Any type that supports the
Choicetrait should also implement the|operator, to enable easy choice/failure propagation. If there is a different implementation ofCombine(rather than accepting the default), then the type should also implement the+operator.ChoiceLawcan help you test your implementation:It also tests the
ApplicativeandFunctorlaws.Types that implement the
Choicetrait:Arr<A>HashSet<A>Iterable<A>Lst<A>Seq<A>Either<L, R>EitherT<L, M, R>Eff<A>Eff<RT, A>IO<A>Fin<A>FinT<M, A>Option<A>OptionT<M, A>Try<A>TryT<M, A>Validation<F, A>Validation<F, M, A>Identity<A>IdentityT<M, A>Reader<E, A>ReaderT<E, M, A>RWST<R, W, S, M, A>State<S, A>StateT<S, M, A>Writer<A>WriterT<M, A>NOTE: Some of those types don't have a natural failure value. For the monad-transformers (like
ReaderT,WriterT, ...) they add aChoiceconstraint on theMmonad that is lifted into the transformer. That allows for theChoiceandCombinebehaviour to flow down the transformer until it finds a monad that has a way of handling the request.For example:
ReaderTcan't handle the+(Combine) request, so it gets passed down the transformer stack, where theSeqhandles it. Resulting in:Similarly for
|:The
Optionknows how to handle|(Choose) and propagates the failure until it gets aSomevalue, resulting in:This is quite elegant I think, but it requires all monads in a stack to implement
Choice. So, a good sensible default (for regular monads without a failure state), is to simply return the first argument (because it always succeeds). That allows all monads to be used in a transformer stack. This isn't ideal, but it's pragmatic and opens up a powerful set of features.Alternative<F>Alternativeis aChoicewith an additionalMonoidK. That augmentsChoicewithEmptyand allows for a default empty state.AlternativeLawcan help you test your implementation:It also tests the
ApplicativeandFunctorlaws.Types that implement the
Alternativetrait:Arr<A>HashSet<A>Iterable<A>Lst<A>Seq<A>Eff<A>Eff<RT, A>IO<A>Fin<A>FinT<M, A>Option<A>OptionT<M, A>Try<A>TryT<M, A>Validation<F, A>Validation<F, M, A>Thanks to @hermanda19 for advocating for the return of the
Alternativetrait, I think I'd gotten a little too close to the code-base and couldn't see the wood for the trees when I removed it a few weeks back. The suggestion to make the trait have a semantically different method name (Choose) re-awoke my brain I think! :DAny thoughts or comments, please let me know below.
This discussion was created from the release Choice and Alternative traits refactor.
Beta Was this translation helpful? Give feedback.
All reactions