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?
The reason why a type annotation is required in
but not in
is due to the difference in type requirements between
mapandreduceLeft.reduceLeftexpectsseqedto return typeBwhereB >: Int. It seems that therefore the precise type forseqedcannot be known, so we have to provide the annotation. More info in this question.One way to overcome this is to re-implement
reduceLeftwithout the lower bound.Test:
The problem now is that this now doesn't work on subtypes of
Seq(e.g.List), with or without the[Int]parameter:reduceLexpects a function of type(List[Int], List[Int]) => List[Int]. BecauseFunction2is defined asFunction2 [-T1, -T2, +R],(Seq[Int], Seq[Int]) => Seq[Int]is not a valid substitution.