Created
March 24, 2012 22:24
-
-
Save mergeconflict/2188596 to your computer and use it in GitHub Desktop.
packaging and unpackaging multiple implicit conversions in an HList
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object AllExamples extends App { | |
import shapeless._ | |
final class All[L <: HList](val values: L) { | |
def apply[A](implicit selector: Selector[L, A]): A = values.select[A] | |
} | |
object All { | |
// package a value of type A, convertible to type B, into an HList containing just B | |
implicit def toAll0[A, B](a: A)(implicit a2b: A => B): All[B :: HNil] = | |
new All(a :: HNil) | |
// package a value of type A, convertible to B and some other types L, into an HList containing B and all types in L | |
implicit def toAll1[A, B, L <: _ :: _](a: A)(implicit a2b: A => B, a2l: A => All[L]): All[B :: L] = | |
new All(a :: a.values) | |
} | |
// example data | |
trait A { def a: String } | |
trait B { def b: String } | |
trait C { def c: String } | |
implicit def intA(n: Int): A = new A { def a = "a " + n.toString } | |
implicit def intB(n: Int): B = new B { def b = "b " + n.toString } | |
implicit def intC(n: Int): C = new C { def c = "c " + n.toString } | |
implicit def stringA(s: String): A = new A { def a = "a " + s } | |
implicit def stringB(s: String): B = new B { def b = "b " + s } | |
implicit def stringC(s: String): C = new C { def c = "c " + s } | |
// implicitly convert int and string values to A, B and Cs | |
val abcs: Seq[All[A :: B :: C :: HNil]] = Seq(1, "haha", 2, "hoho") | |
// unpack | |
for (abc <- abcs) { | |
println(abc[A].a) | |
println(abc[B].b) | |
println(abc[C].c) | |
} | |
} |
Yes, exactly that. Sorry I confused things by mentioning conversions ... I was playing around with something which tried to use a conversion from All[... T ...] to T which got bitten by exactly the same problem.
In my Pack case things are a bit different: the additional structure in the result type (due to the outer type constructor) seems to be enough to allow the inference/resolution to go through. I think having a single argument list with multiple Packs at different type constructors will probably work, but I haven't checked.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hmmm, I'm not sure I understand your explanation about conversions exactly. I didn't think there were any actual conversions taking place at the time when we're trying to unpack
All
. Did you mean that it can't resolve theimplicit selector: Selector[L, A]
evidence until it's inferred a binding forA
, and it can't infer a binding forA
until it's resolved the implicit?I noticed that the way you solved that chicken/egg problem in your
Pack
example was to provideunpack
as an implicit member which you import at the use site. This works I guess because there's only one typeclass there (i.e. theF
inPack[F[_], L <: HList]
)? That is, if you wanted to pack an arbitrary number of typeclass instances you wouldn't be able to do the same trick, right?