Подтвердить что ты не робот

Преобразование кортежа опций в вариант кортежа с помощью Scalaz или Shapeless

Имея

(Some(1), Some(2))

Я ожидаю получить

Some((1, 2))

и имея

(Some(1), None)

Я ожидаю получить

None
4b9b3361

Ответ 1

Вы можете использовать тот факт, что 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 будет компилироваться просто отлично.

Я не могу придумать, почему Scalaз не включил бы что-то вроде этого. Независимо от того, хотите ли вы добавить его в то же время, это вопрос вкуса, но, безусловно, нет теоретического препятствия, позволяющего компилятору печатать здесь.

Ответ 2

Я понимаю, что вы спрашиваете о Scalaz, но стоит отметить, что стандартный метод не является невыносимо многословным:

val x = (Some(1), Some(2))

for (a <- x._1; b <-x._2) yield (a,b)

В общем случае (например, произвольные кортежи) Shapeless лучше всего подходит для такого рода вещей.

Ответ 3

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