2015-12-03 19 views
6

Yeni şekilsiz ve bazı bağımlılıklara ihtiyaç duyan polimorfik fonksiyonların kullanımı hakkında bir sorum var. Temelde bu koduna sahip ve çalışma yönteminin dışına somePoly nesneyi çekmek istiyorum: Ben böyleydi yapmayı düşündünüzBağımlılıkları olan şekilsiz polimorfik fonksiyonların dışarı çekilmesi

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

Bir şekilde, ancak dağınık görünüyor:

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

Herkes herhangi sahip tavsiye?

+0

İlgili gitter tartışması https://gitter.im/milessabin/shapeless?at=56608190d2a5a7813cd41422 – cvogt

cevap

4

Scala'nın örtülü çözünürlük sisteminin sınırlamaları, Poly tanımının kararlı bir tanımlayıcı olması gerektiği anlamına gelir; bu, böyle bir şeyi olması gerekenden daha acı verici hale getirir. Gitter'de belirttiğim gibi, bildiğim birkaç çözüm var (başkaları olabilir).

Bir yaklaşım ekstra argümanlar someInt ve someWord değerler içindir Poly1 bir PolyN, yapmak olacaktır. Bir HList üzerinden eşleme yapıyorsanız, HList girişinin doğru şekle sahip olmasını sağlamak için mapConst ve zip kullanın. Bunu bir coproduct için hiç yapmadım, ama benzer bir şey işe yarayacak.

Başka bir yaklaşım, özel bir tür sınıfı kullanmaktır.

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

Ve sonra run daha genel bir sürümünü yazabiliriz: Senin durumunda bu gibi görünebilir

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

Ve bu gibi kullanmak:

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) 

Operasyonun özgüllüğü bu yaklaşımın biraz garip görünmesine neden oluyor, ama eğer farklı ortak ürünler için böyle bir şey yapmak gerekiyorsa, bu muhtemelen seçeceğim çözüm.

+0

Harika, teşekkürler! – azuras