2015-12-03 17 views
6

Nuovo a informe e ho una domanda sull'uso di funzioni polimorfiche che richiedono alcune dipendenze. Io fondamentalmente ho questo codice e voglia di tirare oggetto somePoly fuori del metodo run:Estrarre le funzioni polimorfiche senza forma che hanno dipendenze

import shapeless._ 
object SomeObject { 
    type SomeType = Int :+: String :+: (String, Int) :+: CNil 

    def run(someList: List[SomeType], someInt:Int, someWord:String) = { 

     object somePoly extends Poly1 { 
      implicit def doIt = at[Int](i => i + someInt + someWord.length) 
      implicit def doIt2 = at[String](i => i.length + someWord.length) 
      implicit def doIt3 = at[(String, Int)](i => i._1.length + someWord.length) 
     } 

     someList.map(_.map(somePoly)) 
    } 
} 

Un modo ho pensato di farlo era come questo, ma sembra disordinato:

object TypeContainer { 
    type SomeType = Int :+: String :+: (String, Int) :+: CNil 
} 
case class SomePolyWrapper(someList: List[TypeContainer.SomeType], someInt:Int, someWord:String){ 
    object somePoly extends Poly1 { 
     implicit def doIt = at[Int](i => i + someInt + someWord.length) 
     implicit def doIt2 = at[String](i => i.length + someWord.length) 
     implicit def doIt3 = at[(String, Int)](i => i._1.length + someWord.length) 
    } 
} 
object SomeObject { 

    def run(someList: List[TypeContainer.SomeType], someInt:Int, someWord:String) = { 

     val somePolyWrapper = SomePolyWrapper(someList, someInt, someWord) 

     someList.map(_.map(somePolyWrapper.somePoly)) 
    } 
} 

Chiunque ha tutte le consigli?

+0

Discussione relativa gitter https://gitter.im/milessabin/shapeless?at=56608190d2a5a7813cd41422 – cvogt

risposta

4

Le limitazioni del sistema di risoluzione implicito di Scala indicano che la definizione Poly deve essere un identificatore stabile, il che rende questo tipo di cose più doloroso di quanto dovrebbe essere. Come ho detto su Gitter, ci sono un paio di soluzioni alternative che conosco (potrebbero essercene altre).

Un approccio potrebbe essere quello di rendere il Poly1 un PolyN, dove gli argomenti extra sono per i valori someInt e someWord. Se stavi mappando su un HList, allora dovresti usare mapConst e zip per rendere l'input HList la forma giusta. Non l'ho mai fatto per un coprodotto, ma è probabile che qualcosa di simile funzioni.

Un altro approccio consiste nell'utilizzare una classe di tipo personalizzata. Nel tuo caso che potrebbe essere simile a questa:

import shapeless._ 

trait IntFolder[C <: Coproduct] { 
    def apply(i: Int, w: String)(c: C): Int 
} 

object IntFolder { 
    implicit val cnilIntFolder: IntFolder[CNil] = new IntFolder[CNil] { 
    def apply(i: Int, w: String)(c: CNil): Int = sys.error("Impossible") 
    } 

    def instance[H, T <: Coproduct](f: (H, Int, String) => Int)(implicit 
    tif: IntFolder[T] 
): IntFolder[H :+: T] = new IntFolder[H :+: T] { 
    def apply(i: Int, w: String)(c: H :+: T): Int = c match { 
     case Inl(h) => f(h, i, w) 
     case Inr(t) => tif(i, w)(t) 
    } 
    } 

    implicit def iif[T <: Coproduct: IntFolder]: IntFolder[Int :+: T] = 
    instance((h, i, w) => h + i + w.length) 

    implicit def sif[T <: Coproduct: IntFolder]: IntFolder[String :+: T] = 
    instance((h, i, w) => h.length + i + w.length) 

    implicit def pif[T <: Coproduct: IntFolder]: IntFolder[(String, Int) :+: T] = 
    instance((h, i, w) => h._1.length + i + w.length) 
} 

E poi si potrebbe scrivere una versione più generica del vostro run:

def run[C <: Coproduct](
    someList: List[C], 
    someInt: Int, 
    someWord: String 
)(implicit cif: IntFolder[C]): List[Int] = someList.map(cif(someInt, someWord)) 

e usarlo in questo modo:

scala> run(List(Coproduct[SomeType](1)), 10, "foo") 
res0: List[Int] = List(14) 

scala> run(List(Coproduct[SomeType](("bar", 1))), 10, "foo") 
res1: List[Int] = List(16) 

La specificità dell'operazione rende questo approccio un po 'strano, ma se avessi davvero bisogno di fare qualcosa del genere per diversi coprodotti, questa è probabilmente la soluzione che sceglierei.

+0

Impressionante, grazie! – azuras

Problemi correlati