2015-12-03 4 views
6

形状がなくなり、いくつかの依存関係が必要な多相関数の使用に関する質問があります。私は基本的にこのコードを持っており、runメソッドのうち、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

関連するジッタの議論https://gitter.im/milessabin/shapeless?at=56608190d2a5a7813cd41422 – cvogt

答えて

4

Scalaの暗黙的な解決システムの限界は、Polyの定義が安定した識別子である必要があることを意味します。私がGitterについて言及したように、私が知っているいくつかの回避策があります(他にもあるかもしれません)。

Poly1PolyNにすることです。余分な引数はsomeIntsomeWordの値です。 HListにマッピングしていた場合は、mapConstzipを使用して、入力をHListにしてください。私はこのような製品を作ったことは一度もありませんが、同様のことが起こりそうです。

もう1つの方法は、カスタムタイプクラスを使用することです。

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

関連する問題