2015-12-03 4 views
6

Новое для бесформенного, и у меня есть вопрос о том, как использовать полиморфные функции, которые нуждаются в некоторых зависимостях. Я в принципе этого кода и хочу, чтобы вытащить somePoly объекта из метода выполнения:Вывод бесформенных полиморфных функций, которые имеют зависимости

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)) 
    } 
} 

Один, как я думал, делать это было так, но мне кажется грязным:

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)) 
    } 
} 

Кто-нибудь есть совет?

+0

Связанные обсуждения gitter https://gitter.im/milessabin/shapeless?at=56608190d2a5a7813cd41422 – cvogt

ответ

4

Ограничения системы неявного разрешения Scala означают, что определение Poly должно быть стабильным идентификатором, что делает этот вид более болезненным, чем должно быть. Как я уже упоминал о Гиттере, есть несколько обходных решений, о которых я знаю (могут быть и другие).

Один подход должен был бы сделать Poly1 в PolyN, где дополнительные аргументы для значений someInt и someWord. Если вы набрали HList, вы должны использовать mapConst и zip, чтобы ввести HList в правильную форму. Я никогда не делал этого для копродукта, но что-то подобное, скорее всего, сработает.

Другим подходом является использование класса пользовательского типа. В вашем случае это может выглядеть примерно так:

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) 
} 

И тогда вы могли бы написать более общую версию run:

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

И использовать его как это:

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) 

Специфика операции делает этот подход немного странным, но если мне действительно нужно сделать что-то подобное для разных копроизведений, это, вероятно, решение, которое я бы выбрал.

+0

Awesome, спасибо! – azuras

Смежные вопросы