J'ai occasionnellement frappé le code comme celui-ci: ou dans mon cas actuel, je veux est là une bonne façon de le faire dans le cas général plan [A, b \ / c] => (MAP [A, B], Map [a, c]) code> p>
f [A \ / b] code> avec des restrictions appropriées sur f? Il semble vaguement comme une variation du thème de Unzip. P> p>
3 Réponses :
Vous pouvez mapper choses code> dans une liste de
(option [A], option [b]) code>, décompressez cette liste dans deux listes, puis unissent le Listes résultantes:
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])
Voici comment nous traitons de cela pour /, mais aussi de la validation, et pas seulement pour les listes, mais d'autres pliables.
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) } } } }
Cela ne couvre pas facilement le boîtier de la carte, car nous finissons par la visualisation de la carte comme une iérienne [(A, B \ / C)] puis divisez-la dans A et B \ / C, mais toujours très utile.
Voici un moyen (pour les listes): et pour une carte: p> Je passe du temps Va venir avec une façon de généraliser cela sur tout f code> (je pense que vous auriez besoin d'instances de
monoïde code> et
applicatif code> pour
f code>). p> p>