2015-12-03 28 views
6

新形狀沒有形狀,我對使用需要某些依賴關係的多態函數有疑問。我基本上有這樣的代碼並想拉somePoly對象了run方法:我認爲這樣做是這樣的拉出具有依賴關係的無形多態函數

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定義需要是一個穩定的標識符,這使得這種事情比它應該更痛苦。正如我在Gitter中所提到的,我知道有幾種解決方法(可能還有其他方法)。

一種方法是使Poly1一個PolyN,其中額外的參數是爲someIntsomeWord值。如果您是通過HList進行映射,則可以使用mapConstzip使輸入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

太棒了,謝謝! – azuras

相關問題