Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type inference on anonymous functions with enrich-my-library

Say I have a method that turns a (function on two elements) into a (function on two sequences):

def seqed[T](f: (T,T) => T): (Seq[T], Seq[T]) => Seq[T] = (_,_).zipped map f

In words, the resulting function takes two sequences xs and ys, and creates a new sequence consisting of (xs(0) f ys(0), xs(1) f ys(1), ...) So, for example, if xss is Seq(Seq(1,2),Seq(3,4)) and f is (a: Int, b: Int) => a + b, we can invoke it thus:

xss reduceLeft seqed(f)         // Seq(4, 6)

or with an anonymous function:

xss reduceLeft seqed[Int](_+_)

This is pretty good; it would be nice to get rid of the [Int] type argument but I don't see how (any ideas?).

To make it feel a bit more like the tupled method, I also tried the enrich-my-library pattern:

class SeqFunction[T](f: (T,T) => T) {
  def seqed: (Seq[T], Seq[T]) => Seq[T] = (_,_).zipped map f
}
implicit def seqFunction[T](f: (T,T) => T) = new SeqFunction(f)

For a pre-defined function this works great, but it's ugly with anonymous ones

xss reduceLeft f.seqed
xss reduceLeft ((_:Int) + (_:Int)).seqed

Is there another way I can reformulate this so that the types are inferred, and I can use syntax something like:

// pseudocode
xss reduceLeft (_+_).seqed         // ... or failing that
xss reduceLeft (_+_).seqed[Int]

? Or am I asking too much of type inference?

like image 524
Luigi Plinge Avatar asked Nov 30 '11 15:11

Luigi Plinge


2 Answers

You can't do it the way you want, but look at Function.tupled, which is a counter-part to .tupled that solves this very same problem.

scala> List(1, 2, 3) zip List(1, 2, 3) map (_ + _).tupled
<console>:8: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$plus(x$2))
              List(1, 2, 3) zip List(1, 2, 3) map (_ + _).tupled
                                                   ^
<console>:8: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.$plus(x$2))
              List(1, 2, 3) zip List(1, 2, 3) map (_ + _).tupled
                                                       ^

scala> List(1, 2, 3) zip List(1, 2, 3) map Function.tupled(_ + _)
res7: List[Int] = List(2, 4, 6)
like image 156
Daniel C. Sobral Avatar answered Nov 15 '22 03:11

Daniel C. Sobral


I am pretty sure you are asking too much. Type inference in Scala goes from left to right, so the type of (_+_) needs to be figured out first before even considering the .sedeq part. And there isn't enough information there.

like image 28
Alexey Romanov Avatar answered Nov 15 '22 03:11

Alexey Romanov