如何将F [A\/ B]拆分为(F [A],F [B])

Ale*_*rab 8 scala scalaz scalaz7

我偶尔会遇到这样的代码:

val things : List[A \/ B] = ???
val (as, bs) : (List[A], List[B]) = ??? //insert something to do this
Run Code Online (Sandbox Code Playgroud)

或者在我目前的情况下我想要 Map[A, B \/ C] => (Map[A, B], Map[A, C])

有没有一种很好的方法在一般情况下F[A \/ B]对F进行适当限制?它看起来有点像Unzip主题的变体.

ste*_*tew 9

以下是我们如何处理这个/但是也可以是Either和Validation,而不仅仅是列表,还有其他可折叠的.

object Uncozip {
  implicit val wtf = language.higherKinds

  // Typeclass which covers sum types such as \/, Either, Validation
  trait Sum2[F[_, _]] {
    def cata[A, B, X](a: A ? X, b: B ? X)(fab: F[A, B]): X
  }

  implicit val sumEither: Sum2[Either] = new Sum2[Either] {
    def cata[A, B, X](a: A ? X, b: B ? X)(fab: Either[A, B]): X = {
      fab match {
        case Left(l)  ? a(l)
        case Right(r) ? b(r)
      }
    }
  }

  implicit val sumEitherz: Sum2[\/] = new Sum2[\/] {
    def cata[A, B, X](a: A ? X, b: B ? X)(fab: A \/ B): X = {
      fab.fold(a(_), b(_))
    }
  }

  implicit val sumValidation: Sum2[Validation] = new Sum2[Validation] {
    def cata[A, B, X](a: A ? X, b: B ? X)(fab: A Validation B): X = {
      fab.fold(a(_), b(_))
    }
  }

  abstract class Uncozips[F[_], G[_, _], A, B](fab: F[G[A, B]]) {
    def uncozip: (F[A], F[B])
  }

  implicit def uncozip[F[_]: Foldable, G[_, _], A, B](fab: F[G[A, B]])(implicit g: Sum2[G], mfa: ApplicativePlus[F], mfb: ApplicativePlus[F]): Uncozips[F, G, A, B] = new Uncozips[F, G, A, B](fab) {
    def uncozip = {
      implicitly[Foldable[F]].foldRight[G[A, B], (F[A], F[B])](fab, (mfa.empty, mfb.empty)) { (l, r) ?
        g.cata[A, B, (F[A], F[B])]({ (a: A) ? (mfa.plus(mfa.point(a), r._1), r._2) },
          { (b: B) ? (r._1, mfa.plus(mfa.point(b), r._2)) })(l)
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)