N-Tuple of Options to Option of N-Tuple
Asked Answered
C

1

6

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?

Coltish answered 13/5, 2015 at 5:34 Comment(0)
H
6

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.

Hardie answered 13/5, 2015 at 21:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.