Given:
case class Foo(a: Option[Int], b: Option[Int], c: Option[Int], d: Option[Int])
I'd like to only allow constructing a Foo
only if at least one of its arguments is Some
, i.e. not all fields are None
.
It would be quite a bit of code to write an Algebraic Data Type, and then make sub-classes for each variant:
sealed trait Foo
case class HasAOnly(a: Int) extends Foo
case class HasAB(a: Int, b: Int) extends Foo
// etc...
Is there a cleaner, i.e. less code, way to address my problem using shapeless
?
You can do something like this with nested Ior
s:
import cats.data.Ior
case class Foo(iors: Ior[Ior[Int, Int], Ior[Int, Int]]) {
def a: Option[Int] = iors.left.flatMap(_.left)
def b: Option[Int] = iors.left.flatMap(_.right)
def c: Option[Int] = iors.right.flatMap(_.left)
def d: Option[Int] = iors.right.flatMap(_.right)
}
Now it's impossible to construct a Foo
with all None
s. You could also make the case class constructor private and have the Ior
logic happen in an alternative constructor on the companion object, which would make pattern matching a little nicer, but it would also make the example a little longer.
Unfortunately this is kind of clunky to use. What you really want is a generalization of Ior
in the same way that shapeless.Coproduct
is a generalization of Either
. I'm not personally aware of a ready-made version of anything like that, though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With