virtualization-lms-core
virtualization-lms-core copied to clipboard
TupledFunctions vs Tuple Function
Imagine a scenario where you want to wrap a third-party higher-order polymorphic function like so:
trait LambdaMap extends ListOps with TupledFunctions {
def map[T: Manifest](l: Rep[List[T]], callback: Rep[T => T]): Rep[List[T]]
}
trait LambdaMapExp extends LambdaMap with ListOpsExp with TupledFunctionsExp {
case class LambdaMap[T:Manifest](l: Exp[List[T]], callback: Exp[T => T]) extends Def[List[T]]
def map[T: Manifest](l: Exp[List[T]], callback: Exp[T => T]): Exp[List[T]] =
LambdaMap(l, callback)
}
trait GenLambdaMap extends ScalaGenListOps with ScalaGenTupledFunctions {
val IR: LambdaMapExp
import IR._
override def emitNode(sym: Sym[Any], rhs: Def[Any]) = rhs match {
case LambdaMap(l,callback) => emitValDef(sym, src"$l.map($callback)")
case _ => super.emitNode(sym, rhs)
}
}
trait LambdaMapUse extends LambdaMap {
def test[T: Manifest](xs: Rep[List[T]]): Rep[List[T]] =
map(xs, fun { x: Rep[T] => x })
}
So generating our 'test' function where T == Double gives us the correct functionality:
class Test extends ((scala.collection.immutable.List[Double])=>(scala.collection.immutable.List[Double])) {
def apply(x0:scala.collection.immutable.List[Double]): scala.collection.immutable.List[Double] = {
val x2 = {x1: (Double) =>
x1: Double
}
val x3 = x0.map(x2)
x3
}
}
While generating our 'test' function where T == (Double, Double) gives us the wrong functionality:
class Test extends ((scala.collection.immutable.List[scala.Tuple2[Double, Double]])=>(scala.collection.immutable.List[scala.Tuple2[Double, Double]])) {
def apply(x0:scala.collection.immutable.List[scala.Tuple2[Double, Double]]): scala.collection.immutable.List[scala.Tuple2[Double, Double]] = {
val x3 = {(x1:Double,x2:Double) =>
((x1,x2)): scala.Tuple2[Double, Double]
}
val x4 = x0.map(x3)
x4
}
}
Due to the autoboxing and unboxing going on with tupled functions I'm not sure how this issue would be resolved? It seems that the 'standard library' of LMS avoids these problems by staging at a different scope e.g. Rep[A] => Rep[B] vs Rep[A => B] with more work being done in the expression layer and generation phase.
I'm not sure if this is a bug or just intended behaviour, so how should I go about this problem? Thanks!