cats icon indicating copy to clipboard operation
cats copied to clipboard

Proposal to add Validated.ensureA[EE >: E, B](A => Validated[EE, B]): Validated[EE, A]

Open SimY4 opened this issue 3 years ago • 14 comments

I sometimes find that I want to run a post-construction verification using validated. The tools that are currently there are:

  • Validated.andThen which requires you to provide a new success even though I want to keep the value I already posess.
  • Validated.ensure in 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.

SimY4 avatar Feb 20 '22 23:02 SimY4

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 avatar Feb 21 '22 00:02 satorg

@satorg yes, exactly.

SimY4 avatar Feb 21 '22 00:02 SimY4

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 avatar Feb 21 '22 01:02 satorg

@satorg one more workaround is using .andThen

valid.andThen { a => ( some validation steps on a ).as(a) }

SimY4 avatar Feb 21 '22 01:02 SimY4

👍 to "flatTap" under some other name.

I found the scaladoc for andThen helpful:

This function is similar to flatMap on Either. It's not called flatMap, because by Cats convention, flatMap is a monadic bind that is consistent with ap.

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.

armanbilge avatar Feb 21 '22 01:02 armanbilge

.andAlso? It has some similarities with Kotlin .also() extension method: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/also.html

SimY4 avatar Feb 21 '22 01:02 SimY4

Bonus points: how can we introduce a "flatten" as well, with similarly consistent naming to andThen 😉

armanbilge avatar Feb 21 '22 01:02 armanbilge

andTap or thenTap ? 🤔

satorg avatar Feb 21 '22 04:02 satorg

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.

morgen-peschke avatar Sep 06 '22 16:09 morgen-peschke

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 avatar Sep 06 '22 16:09 armanbilge

@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.

morgen-peschke avatar Sep 06 '22 19:09 morgen-peschke

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.

johnynek avatar Sep 06 '22 20:09 johnynek

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 avatar Sep 10 '22 14:09 ritschwumm

@ritschwumm I think you are describing the Parallel typeclass :) https://typelevel.org/cats/typeclasses/parallel.html

armanbilge avatar Sep 10 '22 15:09 armanbilge