Как моделировать именованные параметры в вызовах методов с помощью макросов Scala?

Существуют варианты использования, в которых полезно создать копию объекта, который является экземпляром класса case из набора классов case, которые имеют определенное общее значение.

Например, пустьРассмотрим следующие классы дел:

case class Foo(id: Option[Int])
case class Bar(arg0: String, id: Option[Int])
case class Baz(arg0: Int, id: Option[Int], arg2: String)

затемcopy можно вызывать в каждом из этих экземпляров класса case:

val newId = Some(1)

Foo(None).copy(id = newId)
Bar("bar", None).copy(id = newId)
Baz(42, None, "baz").copy(id = newId)

Как описаноВот а такжеВот нет простого способа абстрагировать это так:

type Copyable[T] = { def copy(id: Option[Int]): T }

// THIS DOES *NOT* WORK FOR CASE CLASSES
def withId[T  `type` == returnType
    }
    def hasParameter(name: String, `type`: Type)(implicit method: MethodSymbol) = method.typeSignature match {
      case MethodType(params, _) => params.exists { param =>
        equals(param.name, name) && param.typeSignature == `type`
      }
    }

    // finding method entity.copy(id: Option[Int])
    currentType.members.find { symbol =>
      symbol.isMethod && {
        implicit val method = symbol.asMethod
        hasName("copy") && hasReturnType(currentType) && hasParameter("id", typeOf[Option[Int]])
      }
    } match {
      case Some(symbol) => {
        val method = symbol.asMethod
        val param = reify((
          c.Expr[String](Literal(Constant("id"))).splice,
          id.splice)).tree
        c.Expr(
          Apply(
            Select(
              reify(entity.splice).tree,
              newTermName("copy")),
            List( /*id.tree*/ )))
      }
      case None => c.abort(c.enclosingPosition, currentType + " needs method 'copy(..., id: Option[Int], ...): " + currentType + "'")
    }

  }

}

Последний аргументApply (см. нижнюю часть приведенного выше блока кода) - Список параметров (здесь: параметры метода 'копия»). Как можно датьid типаc.Expr[Option[Int]] передаваться в качестве именованного параметра в метод копирования с помощью нового макро API?

В частности, следующее выражение макроса

c.Expr(
  Apply(
    Select(
      reify(entity.splice).tree,
      newTermName("copy")),
    List(/*?id?*/)))

должно привести к

entity.copy(id = id)

так что имеет место следующее

case class Test(s: String, id: Option[Int] = None)

// has to be compiled by its own
object Test extends App {

  assert( Entity.withId(Test("scala rulz"), Some(1)) == Test("scala rulz", Some(1)))

}

Недостающая часть обозначается местозаполнителем./*?id?*/

Ответы на вопрос(2)

Ваш ответ на вопрос