Convert (A => (M [B], M [C])) to (A => M [(B, C)])

I don’t know the technical terminology for this, but as indicated in the title, I am looking for a function or type class function that converts a function that outputs a pair of containers to a container containing a pair. His signature should look like

def f[M[_], A, B, C](g: A => (M[B], M[C])): A => M[(B, C)]

To achieve this, you may need to first specify a class that allows you to display (M[A], M[B]) => M[(A, B)], and then compose gwith the functionality of this type class.

As a specific example, suppose we have a function f: Int => Option[Int]and a function g: Int => Option[Long]. We can “pair” the functions using the arrow syntax from scalaz ( val h = f &&& g), so that the resulting function ( h) is of type Int => (Option[Int], Option[Long]). Then we can arrange Option, using for understanding or composing (a, b) => a tuple b. How is this generalized?

EDIT:

Shortly after publishing this post, I discovered that the functionality tuplein scalaz7 comes from the class Apply, and not Optiondirectly. This seems to be a weaker class than Applicativethat which explains why this works using monadic understanding. Thus, the Apply application should do its job in the general case. Now my question is: how to convert the source A => (M[B], M[C])directly to A => M[(B, C)]without creating functionality Applywith the function of the original function?

+3
source share
3 answers

Give it a try I have not installed scalaz.

def f[M <: Monad[M[_]], A, B, C](g: A => (M[B], M[C])): A => M[(B, C)] = (a: A) => {
   g(a) match {
     // For general monads, converts (M[B],M[C]) to M[(B, C)]
     case (b, c) => b.map((_, c)).flatMap(k => k._2.map((k._1, _)))
   }
}
0
source

, , , , . , :

  def pairApply[M[_] : Apply, A, B, C](g: A => (M[B], M[C])): A => M[(B, C)] = {
    g andThen (x => implicitly[Apply[M]].tuple2(x._1, x._2))
  }

bazzargh, , scalaz Zip:

  def zipPair[M[_] : Zip, A, B, C](g: A => (M[B], M[C])): A => M[(B, C)] = {
    g andThen (x => x._1 fzip x._2)
  }

.

0

There also bisequence, which allows you to cut a tuple of applications inside out:

def zipPair[M[_]: Applicative, A, B, C](g: A => (M[B], M[C])): A => M[(B, C)] =
  g.andThen(_.bisequence[M, B, C])

This is a little more general than Zipsince it will work with any type with an instance Bitraverse(e.g. Either), and not just with tuples.

0
source

All Articles