Lambda inference and implicit conversions
I have defined the following class:
class TransparentFunction1[-T1, +R1](val func : T1 => R1, val text : String) {
@inline
def apply(t : T1) = func(t)
override def toString = text
}
Basically, TransparentFunction1
it's just a wrapper around Function1
it that provides a human-readable text field describing what the function is.
I would like to define an implicit conversion that can convert any Function1 to TransparentFunction1
by passing the function code to a text parameter.
I have defined such an implicit conversion using a macro:
implicit def transparentFunction1[T1, R1](expression : T1 => R1) : TransparentFunction1[T1, R1] = macro Macros.transparentImpl[T1, R1, TransparentFunction1[T1, R1]]
object Macros {
def transparentImpl[T : context.WeakTypeTag, U : context.WeakTypeTag, V : context.WeakTypeTag](context : scala.reflect.macros.whitebox.Context) (expression : context.Expr[T => U]) : context.Expr[V] = {
import context.universe._
context.Expr[V](
Apply(
Select(
New(
TypeTree(
appliedType(weakTypeOf[V].typeConstructor, weakTypeOf[T] :: weakTypeOf[U] :: Nil)
)
),
termNames.CONSTRUCTOR
),
List(expression.tree, Literal(Constant(expression.tree.toString)))
)
)
}
}
It works. However, this causes a type inference problem.
For example, if I try to call a method named "map" that takes a type argument like TransparentFunction1[Int, Int]
this:
map(_ + 2)
I get the error "Missing parameter type for extended function", whereas if the type of the map parameter was simple Int => Int
, the type inference works correctly.
Is there a way to fix the macro to continue type inference?
source to share
To fix this, you need to have TransparentFunction1
extend Function1
(which seems natural anyway, given that it is TransparentFunction1
conceptually very similar to it Function1
, it just adds a custom one toString
, but should act differently like a simple funciton):
class TransparentFunction1[-T1, +R1](val func : T1 => R1, val text : String) extends (T1 => R1){
@inline
def apply(t : T1) = func(t)
override def toString = text
}
There are only a few reasons I can see for defining a functionally like class that does not extend Function1
. From my point of view, the main reason is that your class is meant to be used as implicit values ββ(like a type) and you don't want the compiler to automatically use those implicit values ββas implicit conversions (which it will if it continues Function1
). It doesn't seem to be the case, so having TransparentFunction1
extend Function1
seems to be correct.
source to share
I don't think there is a way to do this. A while ago I tried to do the same thing for js.FunctionN
in Scala.js (for example, implicitly convert a T1 => R
to js.Function1[T1, R]
) and I could never do a type inference operation for lambda parameters. It seems impossible, unfortunately.
source to share