Extraction of shapeless polymorphic functions having dependencies

New to formless, and I have a question about using polymorphic functions that need some dependencies. I basically have this code and want to get some Poly object out of the run method:

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

One of the ways I thought of doing this was this, but it seems messy:

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

Does anyone have any tips?

+6
source share
1 answer

Scala's implicit permission system limitations mean that the Poly definition must be a stable identifier, which makes this behavior more painful than it should be. As I mentioned about Gitter, there are a few workarounds that I know of (there may be others).

One approach would be to create Poly1 a PolyN , where additional arguments for the values โ€‹โ€‹of someInt and someWord . If you are mapping over an HList , you must use mapConst and zip so that the HList input is HList correct form. I never did this for a co-product, but something like this will probably work.

Another approach is to use a custom type class. In your case, it might look something like this:

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

And then you could write a more general version of your run :

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

And use it as follows:

 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) 

The specifics of the operation makes this approach a little strange, but if I really need to do something similar for different copies, this is probably the solution I would choose.

+4
source

All Articles