2014-12-13 21 views
8

Sto provando a parametrizzare un metodo che deve funzionare su un tipo generico A per il quale è possibile recuperare uno LabelledGeneric. Ecco l'approccio ingenuoPassare un parametro di tipo da utilizzare come argomento LabelledGeneric

case class Foo(bar: String, baz: Boolean) 

def params[A](a: A) = { 
    val lbl = LabelledGeneric[A] 
    val keys = Keys[lbl.Repr].apply 
    ... 
} 

val myThingy = params(Foo) 

Naturalmente, la macro sottostante si lamenta. Non sa abbastanza circa A:

tipo A non è una classe o un tratto


Così, ho cercato di avere la LabelledGeneric dedurre

def params[A](a: A)(implicit lbl: LabelledGeneric[A]) = { 
    val keys = Keys[lbl.Repr].apply 
    ... 
} 

questo sembra per funzionare, ma il tipo Repr non è più uno HList

argomenti di tipo [lbl.Repr] non conformi alle metodo si è applicato il tipo di parametro limiti [L <: shapeless.HList]


Ok, cerchiamo di essere più precisi

def params[A, Repr <: HList](a: A)(implicit lbl: LabelledGeneric.Aux[A, Repr]) = { 
    val keys = Keys[lbl.Repr].apply 
    ... 
} 

Ora, Repr è sicuramente un HList, ma ancora Keys non permette di risolvere i suoi impliciti

non riusciva a trovare il valore implicito per i valori dei parametri: shapeless.ops.record.Values ​​[lbl.Repr]


ultimo tentativo, cerchiamo di avere tutto quello che serve calcolata implicitamente

def params[A, Repr <: HList](a: A)(implicit 
    lbl: LabelledGeneric.Aux[A, Repr], 
    kk: Keys[Repr] 
) = { 
    val keys = kk.apply 
    ... 
} 

Ancora nessuna fortuna, a quanto pare il primo implicita non può essere risolto al sito di chiamata

non poteva trovare valore implicito per il parametro LBL: shapeless.LabelledGeneric.Aux [example.Main.Foo.type, Repr]

[Errore] params (Foo)

Chiaramente tutto questo macchinario opere, quando negoziano direttamente con il tipo specifico, ad es

val lbl = LabelledGeneric[Foo] 
val keys = Keys[lbl.Repr].apply 
// no problem 

che sto chiaramente manca il set necessario di affinamenti sul mio tipo nella firma del metodo, ma posso ottenere la mia testa intorno a ciò che sta succedendo qui. Qualche idea?

+0

Puoi contrassegnarlo con il linguaggio utilizzato? –

+0

@ 500-InternalServerError, naturalmente, il mio male. Fatto –

+0

@GabrielePetronella spiegami, sono un po 'deluso di trovare questo post SO dopo aver passato mezza giornata per trovare quello che ti è stato spiegato – crak

risposta

4

L'ultima variante con tutto calcolato implicitamente funziona per me,

scala> import shapeless._, ops.record._ 
import shapeless._ 
import ops.record._ 

scala> :paste 
// Entering paste mode (ctrl-D to finish) 

def params[A, Repr <: HList](a: A) 
    (implicit lbl: LabelledGeneric.Aux[A, Repr], kk: Keys[Repr]) = { 
    val keys = kk.apply 
    keys 
} 

// Exiting paste mode, now interpreting. 

params: ... 

scala> case class Foo(bar: String, baz: Boolean) 
defined class Foo 

scala> params(foo) 
res0: ... = 'bar :: 'baz :: HNil 

(tipi di risultato elise per migliorare la leggibilità).

+0

oh, stupido. L'errore era passare il costruttore 'Foo', piuttosto che un'istanza. Esiste un modo per guidare l'inferenza del tipo usando invece il metodo di applicazione 'Foo'? Mi piacerebbe ottenere qualcosa come 'params (Foo)' –

+0

Avere il lavoro 'params (Foo)' è possibile, ma abbastanza imbarazzante. Nel contesto, 'params (Foo)' è molto meglio di 'params [Foo]'? –

+0

Sto lavorando su una direttiva spray personalizzata per il routing , quindi alla fine avrò bisogno di usare il metodo 'as' con as (Foo) nella mia implementazione, ecco perché devo passare il costruttore verso il basso –

Problemi correlati