从参数自动推导更高种类的辅助参数

时间:2019-03-29 15:26:35

标签: scala generics typeclass type-level-computation

在较早的SO帖子中,我问如何使用具有更高种类的类型(here,使用Aux模式,得到了很好的答复!)。现在,基于答复,我尝试进一步进行抽象,并从参数的类型中推断出实际的通用参数。麻烦的是,似乎难以区分XX.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 个答案:

答案 0 :(得分:1)

您的对象CaseA处于同一时间

  • 类型为CaseA.type的数字(因为它是单例对象)
  • 类型为CaseA(因为它扩展了CaseA

调用时

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

推断类型PrefixCaseA.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]
}

但是我不确定这是否是您想要的,因为我不知道您想用所有这些花哨的机制来实现什么。