7

I have scalaZ available.

I have an (A, B) and a (A => C, B => D), I'd like to get a (C, D) in a simple and readable way.

I feel like there's something I can do with applicatives but I can't find the right methods.

Daenyth
  • 35,856
  • 13
  • 85
  • 124
  • In Haskell you'd use [`bimap` from the Bifunctor package](http://hackage.haskell.org/package/bifunctors-4.2/docs/Data-Bifunctor.html#v:bimap) – Bergi Feb 18 '15 at 22:27
  • I'll look in scalaz Bifunctor – Daenyth Feb 18 '15 at 22:34
  • http://scalaz.github.io/scalaz/scalaz-2.10-7.0.6/doc/index.html#scalaz.Bifunctor :-) Unfortunately I don't know how to use it (don't know much Scala), so I won't make this an answer – Bergi Feb 18 '15 at 22:36
  • Assuming valTup is your first tuple and funTup is your second. Can't you just write a function to return (funTup._1(valTup._1), funTup._2(valTup._2)) – Lionel Port Feb 18 '15 at 22:42

5 Answers5

5

Edit

Didn't get it at first, that the OP has tuple of functions. In such case as suggested in comments this should work:

val in = ("1", 2)

val fnT = ((s: String) => s.toInt, (i: Int) => i.toString)

val out = (in.bimap[Int, String] _).tupled(fnT)

Old

If you have two functions and want to apply them on tuple, you should be able to do:

import scalaz._
import Scalaz._

val in = ("1", 2)

val sToi = (s: String) => s.toInt
val iTos = (i: Int) => i.toString


val out = sToi <-: in :-> iTos
// or
val out1 = in.bimap(sToi, iTos)
// or
val out2 = (sToi *** iTos)(in)
lpiepiora
  • 13,659
  • 1
  • 35
  • 47
  • 1
    This would work, but would require ripping up the tuple. I think the OP wants something like `funTuple appliedTo tuple2` – Justin Pihony Feb 18 '15 at 22:45
  • 1
    You could apply `tupled` to `bimap` and then pass in the tuple of functions – Ben Reich Feb 18 '15 at 22:56
  • 1
    @BenReich I get compile errors when I try to call `ab.bimap.tupled` - maybe because bimap is supplied via implicit? I'm not sure. The console gives me a different error, `scala> ab.bimap.tupled(fs)` => `error: missing arguments for method bimap in class BifunctorOps; follow this method with `_' if you want to treat it as a partially applied function`, but I can't find any combination of `_` to make it work – Daenyth Feb 18 '15 at 23:04
  • Interesting. I don't use `scalaz` so I didn't test that before I commented, it just seemed like it would work! Maybe it's the implicit, like you said. – Ben Reich Feb 18 '15 at 23:22
  • If you provide the types, you can do: `in.bimap[Int, String] _ tupled tupledFuncs` – Ben Reich Feb 18 '15 at 23:35
3

Arrows? Something like:

(f *** g)(a, b)

http://eed3si9n.com/learning-scalaz/Arrow.html

Victor Moroz
  • 9,167
  • 1
  • 19
  • 23
1

I'm not finding scalaz more readable. Whats wrong with defining your own function.

def biFunc(valTup:(A,B), funTup:((A)=>C,(B)=>D)):(C,D) = (funTup._1(valTup._1), funTup._2(valTup._2))
Lionel Port
  • 3,492
  • 23
  • 26
1

I agree with Lionel Port, but you could make it more readable via:

case class BiFun[A,B,C,D](f1:A=>C, f2: B=>D){
  def applyTo(a: (A,B)) = (f1(a._1), f2(a._2))
} 

object BiFun{  
  implicit def toBiFun(a: (A=>C, B=>D)) = BiFun(a._1, a._2) 
}

used like:

import BiFun._
val ab = (A(1), B(2))
val ac = (x: A) => C(x.i+2)
val bd = (x: B) => D(x.i+2)
val bifn = (ac, bd)
bifn applyTo ab

So, in the end you end up with funTuple applyTo tuple and gain your top level readability

Justin Pihony
  • 66,056
  • 18
  • 147
  • 180
0

Writing this method yourself might be the best bet:

def bimap[A,B,C,D](vals:(A, B), funcs:(A=>C, B=>D)):(C,D) = {
    val ((func1, func2), (val1, val2)) = funcs -> vals
    func1(val1) -> func2(val2)
}

And if you're doing this a lot, you might even enhance the tuple class:

implicit class EnhancedTuple2[A, B](val vals: (A, B)) extends AnyVal {
    def bimap[C, D](funcs: (A=>C, B=>D)) = {
        val ((func1, func2), (val1, val2)) = funcs -> vals
        func1(val1) -> func2(val2)
    }
}

So that you can do:

val func1: Int => Int = x => x * x
val func2: Int => String = x => x.toString
val tupledFuncs = func1 -> func2
(1, 2).bimap(tupledFuncs)
Ben Reich
  • 16,222
  • 2
  • 38
  • 59