假设我有一个类型类,该类型类证明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?
推荐答案此功能与最新的无形2.1.0-SNAPSHOT相同.
This works as written as of the most recent shapeless 2.1.0-SNAPSHOT.
更多推荐
生成类型类实例时无法证明单例类型是单例类型
发布评论