Open fthomas opened 8 years ago
This is a simple and straightforward implementation:
--- a/core/shared/src/main/scala/eu/timepit/refined/internal/RefinePartiallyApplied.scala
+++ b/core/shared/src/main/scala/eu/timepit/refined/internal/RefinePartiallyApplied.scala
@@ -20,4 +21,10 @@ final class RefinePartiallyApplied[F[_, _], P](rt: RefType[F]) {
def force[T](t: T)(implicit v: Validate[T, P]): F[T, P] =
apply(t).fold(err => throw new IllegalArgumentException(err), identity)
+
+ def orNot[T](t: T)(implicit v: Validate[T, P]): Either[F[T, Not[P]], F[T, P]] =
+ v.validate(t) match {
+ case Passed(_) => Right(rt.unsafeWrap(t))
+ case Failed(_) => Left(rt.unsafeWrap(t))
+ }
}
Usage then looks like this:
scala> refineV[Positive].orNot(3)
res1: Either[Refined[Int, Not[Positive]], Refined[Int, Positive]] = Right(3)
scala> refineV[Positive].orNot(-3)
res2: Either[Refined[Int, Not[Positive]], Refined[Int, Positive]] = Left(-3)
This is only half of the story because it won't work with type aliases like type PosInt = Int Refined Positive
.
At the Typelevel Summit in Oslo @non and @dwijnand asked/talked about refining values into a coproduct of a refined type and its "negation", e.g. something like
Either[T Refined Not[P], T Refined P]
. I like this idea and want to explore how this can be implemented and added to refined.