shapeless-contrib czyni to całkiem proste:
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(_))
Wymaga to elementy w argumencie być statycznie wpisane jako 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
Jak Alexandre Archambault wspomniano na Gitter, jest to również możliwe, aby napisać a (a raczej 10), w której bierzesz krotkę z elementami statycznie wpisanymi jako Some
lub None
i uzyskaj wynik statycznie wpisany jako Some
lub None
. Może to mieć zastosowanie w niektórych sytuacjach, ale ogólnie rzecz biorąc, jeśli masz coś statycznie wpisanego jako Some[A]
, powinieneś po prostu go reprezentować jako A
i domyślam się, że prawdopodobnie chcesz wersję mniejszego poziomu.
pamiętać, że bezkształtne-contrib za Sequencer
działa na każdej aplikacyjnej funktora, nie tylko Option
, co oznacza, że można dość łatwo przerobić moje foo
wziąć typ parametru F[_]: Applicative
i zwracają F[T]
. Możesz również rzucić własną, mniej ogólną wersję, która działała tylko pod numerem Option
, a implementacja prawdopodobnie byłaby trochę prostsza niż wersja bezkształtna-contrib.