2015-09-08 18 views
5

Il seguente codice sembra abbastanza ovvio per compilare ed eseguiremappatura sopra HList all'interno di una funzione

case class Pair(a: String, b: Int) 

val pairGen = Generic[Pair] 

object size extends Poly1 { 
    implicit def caseInt = at[Int](x => 1) 
    implicit def caseString = at[String](_.length) 
} 

def funrun(p: Pair) = { 
    val hp: HList = pairGen.to(p) 
    hp.map(size) 
} 

ma il compilatore dice "non riusciva a trovare valore implicito per il parametro mapper". Nel mio caso d'uso, voglio mappare su una HList per ottenere e HList of String (s) e quindi convertire la lista HList di String (s) in Scala [String]. Qualche idea?

risposta

8

Prima possiamo creare un Poly1 simile a size che possiamo utilizzare per mappare un HList a un HList di Strings.

object strings extends Poly1 { 
    implicit def caseInt = at[Int](_.toString) 
    implicit def caseString = at[String](identity) 
} 

si sta già utilizzando Generic[Pair] per trasformare un Pair in un HList, ma non si poteva mappare sopra la vostra hp perché non v'è alcuna prova nella vostra funrun che si può mappare su di esso. Possiamo risolvere questo problema utilizzando parametri impliciti.

def funRun[L <: HList, M <: HList](
    p: Pair 
)(implicit 
    gen: Generic.Aux[Pair, L], 
    mapper: Mapper.Aux[strings.type, L, M] 
) = gen.to(p).map(strings) 
  • Il nostro primo parametro implicito gen può trasformare un Pair in un HList di tipo L.
  • Il nostro secondo parametro implicito mapper può utilizzare il nostro strings funzione polimorfica di mappare un HList di tipo L a un HList di tipo M.

Possiamo ora utilizzare funRun per trasformare un Pair in un HList di Strings:

scala> funRun(Pair("abc", 12)) 
res1: shapeless.::[String,shapeless.::[String,shapeless.HNil]] = abc :: 12 :: HNil 

Ma si voleva restituire un List[String]. Per attivare il nostro HListM (il risultato della mappatura a String) per un List[String] abbiamo bisogno di una ToTraversable, quindi abbiamo aggiungere un terzo parametro implicito:

import shapeless._, ops.hlist._ 

def pairToStrings[L <: HList, M <: HList](
    p: Pair 
)(implicit 
    gen: Generic.Aux[Pair, L], 
    mapper: Mapper.Aux[strings.type, L, M], 
    trav: ToTraversable.Aux[M,List,String] 
): List[String] = gen.to(p).map(strings).toList 

cui possiamo usare come:

scala> pairToStrings(Pair("abc", 12)) 
res2: List[String] = List(abc, 12) 
+0

Grazie @Peter! Questo e 'esattamente quello che stavo cercando! – arapmv

+0

Dopo aver chiuso questa discussione, ho cercato in cerchio di capire perché il seguente miglioramento di base del tipo composito non funziona: 'classe A [T] (val x: T); l'oggetto g estende Poly1 { implicit def caseString = at [String] {identity} }; def toStr [L <: HList] ( un: A [String] ) (implicito gen: Generic.Aux [A [String], L], mapper: Mapper [g.type, L] ) = gen.to (a) .map (g) ' – arapmv

+0

Quale errore ottieni? –