My gut tells me that nothing short of macros or complex type gymnastics can solve this question in the general case. Can Shapeless or Scalaz possibly help me here? Here is a specific instantiation of the problem with N=2, but the solution I'm looking for would hold for all reasonable values of N:
foo((Some(1), Some("bar"))) == Some((1, "bar"))
foo((None, Some("bar"))) == None
foo((Some(1), None)) == None
Again, this is not a duplicate of this question, as I am looking for the general solution for N-Tuples. Answers posed there are specialized to 2-Tuples.
Am I stuck writing a macro, or can Shapeless/Scalaz save the day?
shapeless-contrib makes this pretty easy:
import shapeless._, ops.hlist.Tupler, contrib.scalaz._, scalaz._, Scalaz._
def foo[T, L <: HList, O <: HList](t: T)(implicit
gen: Generic.Aux[T, L],
seq: Sequencer.Aux[L, Option[O]],
tup: Tupler[O]
): Option[tup.Out] = seq(gen.to(t)).map(tup(_))
This requires the elements in the argument to be statically typed as Option
:
scala> foo((some(1), some("bar")))
res0: Option[(Int, String)] = Some((1,bar))
scala> foo((none[Int], some("bar")))
res1: Option[(Int, String)] = None
scala> foo((some(1), none[String]))
res2: Option[(Int, String)] = None
As Alexandre Archambault mentioned on Gitter, it's also possible to write a type-level version (or rather an even more type-level version, I guess) where you take a tuple with elements that are statically typed as Some
or None
and get a result that is statically typed as a Some
or None
. This may have applications in some situations, but in general if you've got something statically typed as a Some[A]
you should just represent it as an A
, and I'm guessing you probably want the less type-level version.
Note that shapeless-contrib's Sequencer
works on any applicative functor, not just Option
, which means you could pretty easily rewrite my foo
to take a F[_]: Applicative
type parameter and return an F[T]
. You could also roll your own less generic version that only worked on Option
, and the implementation would probably be a little simpler than the one in shapeless-contrib.
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