Question

I'm looking for a function that takes a tuple of functions over a common domain and returns a function from that domain to a tuple of their respective outputs. I'm assuming that such a utility is either built into Scala or is tucked away somewhere in Scalaz, but I have been unable to find it.

For example, the special case of a pair of functions (and taking the functions as individual arguments rather than a pair) would look like:

def pairFunc[I, O1, O2](f: I => O1, g: I => O2): I => (O1, O2) = (x: I) => (f(x), g(x))

Is there a way to achieve this for an arbitrary-arity tuple of functions?

EDIT:

A method on a Function type whose output looks like X -> ((A, B), C) and whose construction looks like f fZip g fZip h is just as fine as one a function whose output is X -> (A, B, C).

Was it helpful?

Solution

You're in luck, scalaz (7) does have this with &&&:

  import scalaz._
  import Scalaz._

  val intToString = (i:Int) => i.toString
  val intPlusTwo = (i:Int) => i + 2

  val combined = intToString &&& intPlusTwo

  println(combined(1)) // (1, 3)

And you can continue to combine though it does build up tuples per what your comments would suggest:

  val combinedMore = intToString &&& intPlusTwo &&& intToString

  println(combinedMore(1)) // ((1,3),1)

OTHER TIPS

You can define your own implicits and chain them using view bounds <%

// Add untupling capacity to a simple pair
implicit class EnrichTuple [A, B, C](f: (Function1[A, B], Function1[A, C])) {
  def untuple = (a: A) => (f._1(a), f._2(a))
}
// Add untupling capacity to a pair where the first member can implicitly be untupled
implicit class EnrichTuple2 [A, C, AB <% Function1[A, B] forSome { type B }](f: (AB, Function1[A, C])) {
  def untuple = (a: A) => (f._1(a), f._2(a))
}
// Add untupling capacity to a pair where the second member can implicitly be untupled
implicit class EnrichTuple3 [A, B, AC <% Function1[A, C] forSome { type C }](f: (Function1[A, B], AC)) {
  def untuple = (a: A) => (f._1(a), f._2(a))
}

val intToString = (i:Int) => i.toString
val intPlusTwo = (i:Int) => i + 2
val intTimesFour = (i: Int) => i * 4

val res1 = (intToString, intPlusTwo).untuple
val res2 = ((intToString, intPlusTwo), intTimesFour).untuple
val res3 = (intToString, (intPlusTwo, intTimesFour)).
res1(1)  // Returns (1, 3)
res2(1)  // Returns ((1, 3),4)
res3(1)  // Returns (1, (3, 4))
val res4 = ((intToString, intTimesFour), (intPlusTwo, intTimesFour )).untuple // Error 

The thing you also loose compared to the scalaz solution is the type of the result if there are nested tuples. And besides, you have the requirement that each time at least one of the two arguments of your pair is already a function.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top