Supponiamo che io ho una classe tipo che dimostra che tutti i tipi in un coprodotto Shapeless sono tipi Singleton:non può dimostrare che i tipi di Singleton sono tipi Singleton, mentre la generazione tipo di istanza di classe
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
}
}
Possiamo mostrare che funziona con un semplice ADT:
sealed trait Foo
case object Bar extends Foo
case object Baz extends Foo
E poi:
scala> implicitly[AllSingletons[Foo, Bar.type :+: Baz.type :+: CNil]].values
res0: List[Foo] = List(Bar, Baz)
Ora vogliamo pettine ine questo con Generic
meccanismo di informe che ci daranno una rappresentazione coprodotto della nostra 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
}
}
mi aspetto implicitly[EnumerableAdt[Foo]]
al lavoro, ma non è così. Possiamo usare -Xlog-implicits
di ottenere alcune informazioni sul perché:
<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
ovviamente è un tipo di Singleton, però. Possiamo provare a mettere le Witness
casi in ambito manualmente solo per divertimento:
implicit val barSingleton = Witness[Bar.type]
implicit val bazSingleton = Witness[Baz.type]
E in qualche modo ora funziona:
scala> implicitly[EnumerableAdt[Foo]].values
res1: Set[Foo] = Set(Bar, Baz)
non capisco il motivo per cui queste istanze dovrebbero lavorare in questo contesto mentre quelli generato dal metodo macro Witness.apply
(che abbiamo usato per crearli) no. Cosa sta succedendo qui? C'è una soluzione comoda che non richiede di enumerare manualmente i costruttori?
Ho risolto alcuni bug in quest'area recentemente ... riprovo con l'ultima istantanea? –
Hmm, niente fortuna, stesso risultato. –
Altri tweaks spinti oggi ... terza volta fortunato? –