Автоопределение параметра Aux с более высоким родом из аргумента - PullRequest
0 голосов
/ 29 марта 2019

В более раннем посте SO я спросил, как создать шаблон Aux с типом с более высоким родом ( здесь , у которого был отличный ответ!). Теперь, основываясь на ответе, я пытаюсь продвинуть абстракцию немного, но дальше и сделать вывод о фактическом универсальном параметре из типа аргумента. Проблема в том, что, кажется, возникают проблемы с дифференциацией X от X.type. Вот мой код:

// The are types that I want to convert to various things
sealed trait ConversionType
trait CaseA extends ConversionType
object CaseA extends CaseA // In this case, convert to an optional
trait CaseB extends ConversionType
object CaseB extends CaseB // In this case, convert to a future etc...

trait Converter[Prefix] {
  type Paramd[_]
  def create[N](n:N): Paramd[N]
}

// Create the mechanism to convert from the cases, only doing case A for now...
object Converter {
  type Aux[Prefix, Ret[_]] = Converter[Prefix] { type Paramd[N] = Ret[N] }

  // Shouldn't `Prefix` be automatically inferred?
  def apply[Prefix](prefix:Prefix)(implicit p:Converter[Prefix]): Aux[Prefix, p.Paramd] = p

  implicit def makeOptionParamd: Aux[CaseA, Option] =
    new Converter[CaseA] {
      type Paramd[N] = Option[N]
      override def create[N](n:N): Paramd[N] = Option[N](n)
    }
}

// This works
val v = Converter.apply[CaseA](CaseA).create("test")
// **** This breaks! Why? ****
val vv = Converter.apply(CaseA).create("test")

В пунктирной строке выше встречаются следующие ошибки:

Error:(135, 29) could not find implicit value for parameter p: Test.this.Converter[Test.this.CaseA.type]
    val vv = Converter.apply(CaseA).create("test")

Error:(135, 29) not enough arguments for method apply: (implicit p: Test.this.Converter[SchemaMaker.this.CaseA.type])Test.this.Converter.Aux[SchemaMaker.this.CaseA.type,p.Paramd] in object Converter.
Unspecified value parameter p.
    val vv = Converter.apply(CaseA).create("test")

То есть компилятор не связывает точки между объектом CaseA и типом CaseA? Есть ли способ исправить это?

1 Ответ

1 голос
/ 29 марта 2019

Ваш объект CaseA одновременно

  • типа CaseA.type (потому что это одноэлементный объект)
  • типа CaseA (потому что оно расширяется CaseA)

Когда вы вызываете

val vv = Converter.apply(CaseA).create("test")

выводимый тип Prefix равен CaseA.type (тип объекта-одиночки), и для этого типа не может быть найдено неявного.

Еще более явно:

val works = Converter.apply(CaseA: CaseA).create("test")
val fails = Converter.apply(CaseA: CaseA.type).create("test")

Абсолютно кратчайшее возможное изменение, которое заставит ваш код скомпилироваться, состоит в добавлении одного - перед Prefix, чтобы сделать Converter контравариантным:

trait Converter[-Prefix] {
  type Paramd[_]
  def create[N](n:N): Paramd[N]
}

но я не уверен, что вы этого хотите, потому что я не знаю, чего вы пытаетесь достичь с помощью всего этого причудливого механизма.

...