2014-09-14 13 views
48

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?

+1

Ho risolto alcuni bug in quest'area recentemente ... riprovo con l'ultima istantanea? –

+0

Hmm, niente fortuna, stesso risultato. –

+2

Altri tweaks spinti oggi ... terza volta fortunato? –

risposta

22

Questo funziona come scritto dal più recente shapeless 2.1.0-SNAPSHOT.

Problemi correlati