简体   繁体   English

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

[英]How to split F[A \/ B] into (F[A], F[B])

I occasionally hit code like this: 我偶尔会遇到这样的代码:

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

or in my current case I want Map[A, B \\/ C] => (Map[A, B], Map[A, C]) 或者在我目前的情况下我想要Map[A, B \\/ C] => (Map[A, B], Map[A, C])

Is there a nice way to do this in the general case F[A \\/ B] with appropriate restrictions on F? F[A \\/ B]的一般情况下是否有一个很好的方法来对F进行适当的限制? It looks vaguely like a variation on the theme of Unzip. 它看起来有点像Unzip主题的变体。

Here's how we deal with this for / but also Either and Validation, and not just for Lists, but other Foldable. 以下是我们如何处理这个/但是也可以是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)
      }
    }
  }
}

You can map things in to a list of (Option[A], Option[B]) , unzip that list in to two lists, and then unite the resulting lists: 您可以将things映射到(Option[A], Option[B])列表中,将该列表解压缩到两个列表中,然后将结果列表联合起来:

import scalaz._
import Scalaz._

val things: List[String \/ Int] = List("foo".left, 42.right)
val (strs, ints): (List[String], List[Int]) = things.
  map { d => (d.swap.toOption, d.toOption) }. // List[(Option[String], Option[Int])]
  unzip.                                      // (List[Option[String]], List[Option[Int]])
  bimap(_.unite, _.unite)                     // (List[String], List[Int])

This isn't particularly efficient due to traversing the list three times. 由于遍历列表三次,这不是特别有效。

Here is one way (for lists): 这是一种方式(对于列表):

val things : List[A \/ B] = ???
val (as, bs) = (things.map(_.swap.toList).join, things.map(_.toList).join)

And for a map: 而对于地图:

val things: Map[String, String \/ Int] = ???
val (as, bs) = (things.mapValues(_.swap.toList).filterNot(e => e._2.isEmpty), 
                things.mapValues(_.toList).filterNot(e => e._2.isEmpty))

I'm having a hard time coming up with a way to generalize this over any F (I believe you would need instances of Monoid and Applicative for F ). 我有一个很难拿出一个办法在任何概括这个F (我相信你会需要的情况下, MonoidApplicativeF )。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何将F [Either [A,B]]转换为Either [F [A],F [B]] - How to transform F[Either[A, B]] to Either[F[A], F[B]] Scala中f(a,b)和f(a)(b)之间的差异 - Difference between f(a,b) and f(a)(b) in Scala 函数等价于if(p(f(a),f(b))a else b - Functional equivalent of if (p(f(a), f(b)) a else b 将&#39;A =&gt; F [G [B]]&#39;转换为&#39;F [G [A =&gt; B]&#39;标量 - transform 'A => F[G[B]]' into 'F[G[A=>B]' scala def compose [A,B,C](f:B =&gt; C,g:A =&gt; B):A =&gt; C = {f(g(_))}是不是有效的Scala声明? - def compose[A,B,C](f: B => C, g: A => B): A => C = {f(g(_))} is noty valid scala declaration? 电梯[A,B]中下划线的含义(f:A => B):选项[A] =>选项[B] = _映射f - Meaning of underscore in lift[A,B](f: A => B): Option[A] => Option[B] = _ map f Scala如何将Seq [(((A,B,C,D),Seq [(E,F,G)])]]转换为Seq [(A,B,C,D,Seq [(E,F,G) ])]? - Scala How to transform Seq[((A, B, C, D), Seq[(E, F, G)])] to Seq[(A, B, C, D, Seq[(E, F, G)])]? `F[_ &lt;: A] &lt;: B` 在类型级别和 `f: A =&gt; B` 在值级别之间的类比 - Analogy between `F[_ <: A] <: B` at type-level and `f: A => B` at value-level 具有两个类型参数(即F [A,B]等于AFB)的仿制药的合成糖在哪里记录? - Where is synthetic sugar for generics with two type parameters (ie. that F[A,B] is equal to A F B) documented? 将Hlist [F [A]]转换为F [B],其中案例类B与A对齐类型 - Transforming a Hlist[F[A]] into F[B] where case class B has aligned types with A
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM