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
map
andreduceLeft
.reduceLeft
expectsseqed
to return typeB
whereB >: Int
. It seems that therefore the precise type forseqed
cannot be known, so we have to provide the annotation. More info in this question.One way to overcome this is to re-implement
reduceLeft
without 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:reduceL
expects a function of type(List[Int], List[Int]) => List[Int]
. BecauseFunction2
is defined asFunction2 [-T1, -T2, +R]
,(Seq[Int], Seq[Int]) => Seq[Int]
is not a valid substitution.