持つ
(Some(1), Some(2))
私は得ることを期待しています
Some((1, 2))
そして持つ
(Some(1), None)
私は得ることを期待しています
None
あなたが Scalaz について質問しているのは承知していますが、標準的な方法は耐え難いほど冗長ではないことを指摘しておく価値があります。
val x = (Some(1), Some(2))
for (a <- x._1; b <-x._2) yield (a,b)
一般的なケース (任意のアリティのタプルなど) では、Shapelessはこの種の処理に最適です。
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 がこのようなものを含めない正当な理由が思いつきません。それまでに追加するかどうかは好みの問題ですが、ここでコンパイラーに型付けを行わせることに理論的な障害はまったくありません。
scala> 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