无法在生成类型类实例时证明单例类型是单例类型

无法在生成类型类实例时证明单例类型是单例类型

本文介绍了无法在生成类型类实例时证明单例类型是单例类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个类型类来证明 Shapeless 余积中的所有类型都是单例类型:

Suppose I've got a type class that proves that all the types in a Shapeless coproduct are singleton types:

import shapeless._

trait AllSingletons[A, C <: Coproduct] {
  def values: List[A]
}

object AllSingletons {
  implicit def cnilSingletons[A]: AllSingletons[A, CNil] =
    new AllSingletons[A, CNil] {
      def values = Nil
    }

  implicit def coproductSingletons[A, H <: A, T <: Coproduct](implicit
    tsc: AllSingletons[A, T],
    witness: Witness.Aux[H]
  ): AllSingletons[A, H :+: T] =
    new AllSingletons[A, H :+: T] {
      def values = witness.value :: tsc.values
    }
}

我们可以证明它与简单的 ADT 一起工作:

We can show that it works with a simple ADT:

sealed trait Foo
case object Bar extends Foo
case object Baz extends Foo

然后:

scala> implicitly[AllSingletons[Foo, Bar.type :+: Baz.type :+: CNil]].values
res0: List[Foo] = List(Bar, Baz)

现在我们想将它与 Shapeless 的 Generic 机制结合起来,这将为我们提供 ADT 的联积表示:

Now we want to combine this with Shapeless's Generic mechanism that'll give us a coproduct representation of our ADT:

trait EnumerableAdt[A] {
  def values: Set[A]
}

object EnumerableAdt {
  implicit def fromAllSingletons[A, C <: Coproduct](implicit
    gen: Generic.Aux[A, C],
    singletons: AllSingletons[A, C]
  ): EnumerableAdt[A] =
    new EnumerableAdt[A] {
      def values = singletons.values.toSet
    }
}

我希望 implicitly[EnumerableAdt[Foo]] 起作用,但它没有.我们可以使用 -Xlog-implicits 来获取有关原因的一些信息:

I'd expect implicitly[EnumerableAdt[Foo]] to work, but it doesn't. We can use -Xlog-implicits to get some information about why:

<console>:17: shapeless.this.Witness.apply is not a valid implicit value for
  shapeless.Witness.Aux[Baz.type] because:
Type argument Baz.type is not a singleton type
              implicitly[EnumerableAdt[Foo]]
                        ^
<console>:17: this.AllSingletons.coproductSingletons is not a valid implicit
  value for AllSingletons[Foo,shapeless.:+:[Baz.type,shapeless.CNil]] because:
hasMatchingSymbol reported error: could not find implicit value for parameter
  witness: shapeless.Witness.Aux[Baz.type]
              implicitly[EnumerableAdt[Foo]]
                        ^
<console>:17: this.AllSingletons.coproductSingletons is not a valid implicit
  value for AllSingletons[Foo,this.Repr] because:
hasMatchingSymbol reported error: could not find implicit value for parameter
  tsc: AllSingletons[Foo,shapeless.:+:[Baz.type,shapeless.CNil]]
              implicitly[EnumerableAdt[Foo]]
                        ^
<console>:17: this.EnumerableAdt.fromAllSingletons is not a valid implicit
  value for EnumerableAdt[Foo] because:
hasMatchingSymbol reported error: could not find implicit value for parameter
  singletons: AllSingletons[Foo,C]
              implicitly[EnumerableAdt[Foo]]
                        ^
<console>:17: error: could not find implicit value for parameter e:
  EnumerableAdt[Foo]
              implicitly[EnumerableAdt[Foo]]
                        ^

不过,

Baz.type 显然 一个单例类型.我们可以尝试将 Witness 实例手动放入范围内,只是为了好玩:

Baz.type obviously is a singleton type, though. We can try putting the Witness instances in scope manually just for fun:

implicit val barSingleton = Witness[Bar.type]
implicit val bazSingleton = Witness[Baz.type]

不知何故现在它起作用了:

And somehow now it works:

scala> implicitly[EnumerableAdt[Foo]].values
res1: Set[Foo] = Set(Bar, Baz)

我不明白为什么这些实例可以在这种情况下工作,而由 Witness.apply 宏方法(我们用来创建它们)生成的实例却不能.这里发生了什么?有没有不需要我们手动枚举构造函数的方便的解决方法?

I don't understand why these instances would work in this context while the ones generated by the Witness.apply macro method (which we used to create them) don't. What's going on here? Is there a convenient workaround that doesn't require us to enumerate the constructors manually?

推荐答案

这与最新的 shapeless 2.1.0-SNAPSHOT 一样有效.

This works as written as of the most recent shapeless 2.1.0-SNAPSHOT.

这篇关于无法在生成类型类实例时证明单例类型是单例类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-19 12:36