Proposal to add Validated.ensureA[EE >: E, B](A => Validated[EE, B]): Validated[EE, A]
I sometimes find that I want to run a post-construction verification using validated. The tools that are currently there are:
-
Validated.andThenwhich requires you to provide a new success even though I want to keep the value I already posess. -
Validated.ensurein which you can't report more than one failure in one go.
So I wanted to propose a method:
Validated#ensureA[EE >: E, B](check: A => Validated[EE, B]): Validated[EE, A]
that will let run an arbitrary number of post verification steps keeping the original value A in one go.
Just to clarify: ensureA looks quite similar to FlatMap#flatTap in its shape, isn't it?
def flatTap[A, B](fa: F[A])(f: A => F[B]): F[A] =
flatMap(fa)(a => as(f(a), a))
@satorg yes, exactly.
Technically (as a work-around), it can be achieved by converting a Validated to Either temporarily, making a call to flatTap and then converting the result back to Validated. There's a method withEither in Validated which can come handy:
https://scastie.scala-lang.org/satorg/YakeDr4QRK6NBLHFKhIqlQ/5
But I agree that it still looks quite wordy. So perhaps a flatTap-like method could be a useful addition for Validated. Although I am not sure that ensureA is really good name for it.
@satorg one more workaround is using .andThen
valid.andThen { a => ( some validation steps on a ).as(a) }
👍 to "flatTap" under some other name.
I found the scaladoc for andThen helpful:
This function is similar to
flatMaponEither. It's not calledflatMap, because by Cats convention,flatMapis a monadic bind that is consistent withap.
So if we can have "flatMap" under the name andThen, I don't see why we can't have "flatTap" as well. Would be cool if the name retained some connection to andThen.
.andAlso? It has some similarities with Kotlin .also() extension method: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/also.html
Bonus points: how can we introduce a "flatten" as well, with similarly consistent naming to andThen 😉
andTap or thenTap ? 🤔
Along those same lines, because andThen exists, the lack of something like flatTraverse makes itself felt rather keenly if you're doing most of your validation in Validated.
I use andThenF, but something native to Validated would be nice.
Validated can't have a FlatMap that's lawful (or at least my attempts to write one have been an abject failure), but it does feel like there's an abstraction missing here to bridge the gap.
Recently my understanding is that using Either as your primary data type should be preferred and calling par* methods when you need Validated-semantics. Perhaps Parallel is the "missing bridge" you are looking for? :)
@armanbilge : Possibly. I usually use Validated as the default, and drop to Either-semantics via .andThen when needed (as that seems to be less often), so it could be that my use patterns are just a bit odd.
side note: I think cooking up all new names just because we don't provide an implicit Monad[Validated[E, *]] I'm not sure if that justifies renaming methods that work exactly like their monadic counterparts.
I'm 100% behind not making a Monad of course (that's the point), but consider teaching the explanation for why .andThen is exactly the same as .flatMap on the Parallel monad instance, but we just don't want to name it that here.
do we need a typeclass for "this is a monad, but it's the one for the wrong applicative "? probably a very stupid idea...
@ritschwumm I think you are describing the Parallel typeclass :)
https://typelevel.org/cats/typeclasses/parallel.html