не удалось найти неявное значение для shapeless.ops.record.Selector - PullRequest
0 голосов
/ 19 марта 2019

Я играю с бесформенным, чтобы исследовать возможность извлечения типа значения в бесформенной помеченной записи.Мотивация заключается в том, что я могу затем использовать классы типов и имплициты для отправки потока процесса на основе типа.Однако следующий код не работает.

import shapeless._, record._
import shapeless.ops.record.Selector
import shapeless.syntax.RecordOps
import shapeless.syntax.singleton._

object ShapelessRecordTest extends App {

  trait Extractor[K, T] {
    type OUT_K
    def extract: T => OUT_K
  }

  object Extractor {

    type Aux[K, T, OUT_K0] = Extractor[K, T] {
      type OUT_K = OUT_K0
    }

    implicit def apply[T, Repr, OUT](k: Witness)(
      implicit gen: LabelledGeneric.Aux[T, Repr],
      selector: Selector.Aux[Repr, k.T, OUT]
    ): Aux[k.T, T, OUT] = new Extractor[k.T, T] {
      type OUT_K = OUT
      def extract: T => OUT_K = (e: T) => {
        val rep = gen.to(e)
        val rprOp: RecordOps[Repr] = new RecordOps[Repr](rep)
        rprOp(k)
      }
    }
  }

  case class Person(name: String, address: String, age: Int)

  implicit val gen = LabelledGeneric[Person]

  val nameWit: Witness = 'name
  val nameExtractor: Extractor.Aux[nameWit.T, Person, String] = Extractor(nameWit)

  def main(args: Array[String]): Unit = {
    val joe = Person("Joe", "Brighton", 33)
    println(nameExtractor.extract(joe))
  }

}

Я использую Scala 2.12.8, и ошибка компилятора

{
    "resource": "/workspace/connecterra/stream-data-pipeline/flink/src/main/scala/io/connecterra/ShapelessRecordTest.scala",
    "owner": "_generated_diagnostic_collection_name_#0",
    "severity": 8,
    "message": "could not find implicit value for parameter selector: shapeless.ops.record.Selector.Aux[Repr,ShapelessRecordTest.nameWit.T,OUT]",
    "source": "scalac",
    "startLineNumber": 37,
    "startColumn": 74,
    "endLineNumber": 37,
    "endColumn": 75
}

Я хотел бы понять, чего мне здесь не хватает,Или это вообще возможно в бесформенном состоянии?

1 Ответ

2 голосов
/ 19 марта 2019

Нет особого смысла делать apply неявным, если вы собираетесь вызывать его явно. Лучше не смешивать материализующий метод и неявный метод, определяющий экземпляры класса типа. RecordOps не предполагается создавать вручную (для этого есть import shapeless.record._). Иногда лучше вызывать apply метод класса типа (например, shapeless.ops.record.Selector) напрямую, чем полагаться на методы расширения. Когда вы пишете val nameWit: Witness = 'name, вы теряете уточнение типа. Нет смысла создавать implicit val gen = LabelledGeneric[Person]. Для Selector, Repr должно быть <: HList.

Попробуйте

import shapeless._
import shapeless.ops.record.Selector

object ShapelessRecordTest {

  trait Extractor[K, T] {
    type OUT_K
    def extract: T => OUT_K
  }

  object Extractor {

    type Aux[K, T, OUT_K0] = Extractor[K, T] {
      type OUT_K = OUT_K0
    }

    def apply[T](k: Witness)(implicit 
      extractor: Extractor[k.T, T]): Aux[k.T, T, extractor.OUT_K] = extractor

    implicit def extractor[T, Repr <: HList, K](implicit
      gen: LabelledGeneric.Aux[T, Repr],
      selector: Selector[Repr, K]
    ): Aux[K, T, selector.Out] = new Extractor[K, T] {
      type OUT_K = selector.Out
      def extract: T => OUT_K = (e: T) => {
        val rep: Repr = gen.to(e)
        selector(rep)
      }
    }
  }

  case class Person(name: String, address: String, age: Int)

  val nameWit = Witness('name)
  val nameExtractor: Extractor.Aux[nameWit.T, Person, String] = Extractor(nameWit)

  def main(args: Array[String]): Unit = {
    val joe = Person("Joe", "Brighton", 33)
    println(nameExtractor.extract(joe)) // Joe
  }
}
...