Làm thế nào để sử dụng Shapless trong Quasiquote?


272

Tôi đang cố gắng để gọi một Shapelessvĩ mô từ một bên quasiquotevới Scalavà tôi không nhận được những gì tôi muốn có được.

Macro của tôi không trả về bất kỳ lỗi nào nhưng nó không mở rộng Witness(fieldName)thànhWitness.Lt[String]

val implicits = schema.fields.map { field =>
  val fieldName:String = field.name
  val fieldType = TypeName(field.valueType.fullName)
  val in = TermName("implicitField"+fieldName)
  val tn = TermName(fieldName)
  val cc = TermName("cc")
  q"""implicit val $in = Field.apply[$className,$fieldType](Witness($fieldName), ($cc:   $className) => $cc.$tn)"""
}

Đây là Fieldđịnh nghĩa của tôi :

sealed abstract class Field[CC, FieldName] {
  val  fieldName: String
  type fieldType

  // How to extract this field
  def  get(cc : CC) : fieldType
}

object Field {
  // fieldType is existencial in Field but parametric in Fied.Aux
  // used to explict constraints on fieldType
  type Aux[CC, FieldName, fieldType_] = Field[CC, FieldName] {
    type fieldType = fieldType_
  }

  def apply[CC, fieldType_](fieldWitness : Witness.Lt[String], ext : CC => fieldType_) : Field.Aux[CC, fieldWitness.T, fieldType_] =
    new Field[CC, fieldWitness.T] {
      val fieldName  : String = fieldWitness.value
      type fieldType = fieldType_
      def get(cc : CC) : fieldType = ext(cc)
    }
}

Trong trường hợp này, ẩn tôi tạo ra trông giống như:

implicit val implicitFieldname : Field[MyCaseClass, fieldWitness.`type`#T]{
  override type fieldType = java.lang.String
}

Nếu nó đã được xác định bên ngoài, quasiquotenó sẽ tạo ra một cái gì đó như:

implicit val implicitFieldname : Field.Aux[MyCaseClass, Witness.Lt[String]#T, String] = ...

Có một cái gì đó có thể được thực hiện?


Bạn đang sử dụng điều này trong một chú thích vĩ mô? Bạn đã thử cung cấp một chú thích loại cho $in(mà tôi nghĩ sẽ yêu cầu sử dụng ConstantType)?
Travis Brown

@TravisBrown có Tôi đang xây dựng điều này bằng cách sử dụng chú thích macro (Thiên đường vĩ mô). Tôi đã cố gắng cung cấp một loại như thế này:q"""implicit val $in : Field.Aux[$className, Witness.Lt[String]#T, String] = Field.apply[$className,$fieldType](Witness($fieldName), ($cc: $className) => $cc.$tn)"""
Roch

Tuy nhiên, bạn sẽ cần tên trường cụ thể trong chú thích loại (xem ví dụ: bài đăng blog trước Shapless 2.0 cũ của tôi ở đây để biết ví dụ về việc sử dụng ConstantType). Bạn có tình cờ có một ví dụ làm việc hoàn chỉnh xung quanh?
Travis Brown

Câu trả lời:


1

Đây là giải pháp làm việc của tôi bằng cách sử dụng các chú thích macro kiểu cũ.

import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
import scala.annotation.StaticAnnotation

class fieldable extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro fieldableMacro.impl
}

object fieldableMacro {
  def impl(c: Context)(annottees: c.Expr[Any]*): c.Tree = {
    import c.universe._
    annottees.map(_.tree) match {
      case (param @ q"case class $className(..$fields)") :: Nil => {
        val implicits = fields.collect {
          case field @ q"$mods val $tname: $tpt" => q"""
            implicit val $tname = Field.apply[$className,$tpt](
              Witness(${tname.decodedName.toString}), _.$tname
            )"""
        }; q"$param; object ${className.toTermName} {..$implicits}"
      }
    }
  }
}

Chắc chắn, nó có thể được cải thiện bằng cách sử dụng các chuẩn tinh tốt hơn, nhưng mục tiêu của tôi là hiển thị thứ gì đó càng sạch càng tốt.

Nó có thể được sử dụng như:

@fieldable
case class MyCaseClass(foo: String, bar: Int)

Điều này tạo ra một MyCaseClassđối tượng đồng hành có yêu cầu Fieldsẩn ý:

implicit val foo = Field.apply[MyCaseClass, String](Witness("foo"), ((x$1) => x$1.foo));
implicit val bar = Field.apply[MyCaseClass, Int](Witness("bar"), ((x$2) => x$2.bar));

Như đã được chỉ ra, nếu không có một ví dụ hoạt động hoàn chỉnh, thật khó để viết một câu trả lời thấu đáo.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.