I have some Scala code that does something nifty with two different versions of a type-parameterized function. I have simplified this down a lot from my application but in the end my code full of calls of the form w(f[Int],f[Double])
where w()
is my magic method. I would love to have a more magic method like z(f) = w(f[Int],f[Double])
- but I can't get any syntax like z(f[Z]:Z->Z)
to work as it looks (to me) like function arguments can not have their own type parameters. Here is the problem as a Scala code snippet.
Any ideas? A macro could do it, but I don't think those are part of Scala.
object TypeExample {
def main(args: Array[String]):Unit = {
def f[X](x:X):X = x // parameterize fn
def v(f:Int=>Int):Unit = { } // function that operates on an Int to Int function
v(f) // applied, types correct
v(f[Int]) // appplied, types correct
def w[Z](f:Z=>Z,g:Double=>Double):Unit = {} // function that operates on two functions
w(f[Int],f[Double]) // works
// want something like this: def z[Z](f[Z]:Z=>Z) = w(f[Int],f[Double])
// a type parameterized function that takes a single type-parameterized function as an
// argument and then speicalizes the the argument-function to two different types,
// i.e. a single-argument version of w() (or wrapper)
}
}
You can do it like this:
trait Forall {
def f[Z] : Z=>Z
}
def z(u : Forall) = w(u.f[Int], u.f[Double])
Or using structural types:
def z(u : {def f[Z] : Z=>Z}) = w(u.f[Int], u.f[Double])
But this will be slower than the first version, since it uses reflection.
EDIT: This is how you use the second version:
scala> object f1 {def f[Z] : Z=>Z = x => x}
defined module f1
scala> def z(u : {def f[Z] : Z=>Z}) = (u.f[Int](0), u.f[Double](0.0))
z: (AnyRef{def f[Z]: (Z) => Z})(Int, Double)
scala> z(f1)
res0: (Int, Double) = (0,0.0)
For the first version add f1 extends Forall
or simply
scala> z(new Forall{def f[Z] : Z=>Z = x => x})