Lambda类型推断和隐式转换

时间:2015-07-15 15:45:47

标签: scala scala-macros

我已经定义了以下类:

class TransparentFunction1[-T1, +R1](val func : T1 => R1, val text : String) {
  @inline
  def apply(t : T1) = func(t)

  override def toString = text
}

基本上,TransparentFunction1只是Function1的包装器,它提供了一个描述函数内容的人类可读文本字段。

我想定义一个隐式转换,可以将任何Function1转换为TransparentFunction1,并将函数的代码传递给text参数。

我已经使用宏定义了这种隐式转换:

  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)))
        )
      )
    }
}

这很有效。但是,它会导致类型推断出现问题。

例如,如果我尝试调用一个名为&#34的方法; map"它采用类型为TransparentFunction1[Int, Int]的参数:

map(_ + 2)

我收到错误"缺少扩展函数"的参数类型,而如果map的参数类型只是Int => Int,则类型推断可以正常工作。

有没有办法修复宏,以便类型推断继续有效?

1 个答案:

答案 0 :(得分:2)

要解决此问题,您只需要TransparentFunction1延长Function1(这似乎很自然,因为TransparentFunction1在概念上非常Function1,它只是添加了一个自定义toString,但应该作为一个普通的功能):

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
}

我只能看到一小部分理由来定义类似函数的类扩展Function1。在我的脑海中,主要原因是当你的类被设计为用作隐式值(例如类型类)时,你不希望编译器自动将这些隐式值用作隐式转换(它将会如果它延伸Function1)。这似乎并非如此,因此TransparentFunction1扩展Function1似乎是正确的做法。