Having
(Some(1), Some(2))
I expect to get
Some((1, 2))
并且拥有
(Some(1), None)
I expect to get
None
我知道你在询问Scalaz,但值得指出的是标准方法并不过于冗长:
val x = (Some(1), Some(2))
for (a <- x._1; b <-x._2) yield (a,b)
在一般情况下(例如任意元组的情况),Shapeless 是最擅长这种事情的工具。
Traverse
实例,但是Bitraverse
可以让你在其中获取两种类型。 - Travis Brown您可以利用 Scalaz 7 提供的元组 Bitraverse
实例,然后像平常一样使用 bisequence
(而不是 sequence
) 进行序列化:
scala> import scalaz._, std.option._, std.tuple._, syntax.bitraverse._
import scalaz._
import std.option._
import std.tuple._
import syntax.bitraverse._
scala> val p: (Option[Int], Option[String]) = (Some(1), Some("a"))
p: (Option[Int], Option[String]) = (Some(1),Some(a))
scala> p.bisequence[Option, Int, String]
res0: Option[(Int, String)] = Some((1,a))
很遗憾,目前Scalaz 7需要在此处加上类型注释。
根据Yo Eight在评论中的说法,类型注释仍然是必需的。我不确定他或她的理由是什么,但实际上很容易编写自己的包装器,该包装器将为任何适当类型的元组提供bisequence方法,并且不需要类型注释:
import scalaz._, std.option._, std.tuple._
class BisequenceWrapper[F[_, _]: Bitraverse, G[_]: Applicative, A, B](
v: F[G[A], G[B]]
) {
def bisequence = implicitly[Bitraverse[F]].bisequence(v)
}
implicit def bisequenceWrap[F[_, _]: Bitraverse, G[_]: Applicative, A, B](
v: F[G[A], G[B]]
) = new BisequenceWrapper(v)
现在(some(1), some("a")).bisequence
将能够正常编译。
我想不出为什么Scalaz不会包含这样的东西。无论是否想要在此期间添加它都是品味问题,但在让编译器处理类型方面肯定没有理论障碍。
Bitraverse
和Applicative
实例的证据。 - Travis Brown我认为这里不会重复使用Cats的版本。
@ import cats.implicits._
import cats.implicits._
@ (4.some, 2.some).bisequence
res1: Option[(Int, Int)] = Some((4, 2))
@ (4.some, none).bisequence
res2: Option[Tuple2[Int, Nothing]] = None
Starting Scala 2.13
, this exact behavior is provided in the standard library by Option#zip
:
Some(2) zip Some('b') // Some((2, 'b'))
Some(2) zip None // None
None zip Some('b') // None
None zip None // None
Before Scala 2.13
, Option#zip
was returning an Iterable
and it was possible to combine it with headOption
:
Some(2) zip Some('b') headOption // Some((2, 'b'))
Some(2) zip None headOption // None
Tuple2<Option<K>, Option<V>> -> Option<Tuple2<K,V>>
,而zip
提供的是(多多少少)Option<T1> -> Option<T2> -> Option<Tuple2<T1, T2>>
。 - undefinedopposite
的使用感到困惑。初始Tuple2<Option<K>, Option<V>>
的每个部分都可以按顺序访问,以达到此答案的输入状态(tuple._1 zip tuple._2
)。决定不包含那部分,因为提取元组的部分是相当明显的,有趣的部分是zip
的部分。 - undefinedscala> import scalaz._
import scalaz._
scala> import Scalaz._
import Scalaz._
scala> (Tuple2.apply[Int, Int] _).lift[Option].tupled
res5: (Option[Int], Option[Int]) => Option[(Int, Int)] = <function1>
scala> res5((some(3), some(11)))
res6: Option[(Int, Int)] = Some((3,11))
scala> res5((some(3), none))
res7: Option[(Int, Int)] = None
res5 = uncurry $ liftA2 (,)
。 - missingfaktor
val (aOpt, bOpt) = optPair; aOpt.flatMap(a => bOpt.map(b => (a, b)))
? - Erik Kaplun