I want to find out if a particular class member is present in a given case class or not.
Following does give me that answer, failing at compile time which is right. (credit to Travis Brown)
scala> def getIntId[A, R <: HList](a: A)(implicit
| gen: LabelledGeneric.Aux[A, R],
| sel: Selector.Aux[R, Witness.`'id`.T, Int]
| ): Int = sel(gen.to(a))
case class Foo(id: String)
case class Bar(id: Int, name: String)
scala> getIntId(Bar(123, "bar"))
res3: Int = 123
scala> getIntId(Foo("12345"))
<console>:15: error: could not find implicit value for parameter sel: shapeless.ops.record.Selector.Aux[R,Symbol with shapeless.tag.Tagged[String("id")],Int]
getIntId(Foo("12345"))
Now if I don't have a concrete type but T to pass into getIntId method, is there a way to get this to work with generic type T ?
Update
Say have a method called findIdFromType as described below which takes in type T (where T will always be a some case class). is it possible to make this work?
def findIdFromType[T](t:T) = {
getIntId(t) //as expected doesn't compile
}
getIntId requires two implicit parameters.
If you need to call it in the context of a local method, you need to prove that those parameters exist in such context.
In order to do so, you have to propagate the implicit evidence, like this
def findIdFromType[A, R <: HList](a: A)(implicit
gen: LabelledGeneric.Aux[A, R],
sel: Selector.Aux[R, Witness.`'id`.T, Int]): Int = getIntId(a)
This of course is a completely useless example, but in case you want to perform other operations inside the wrapping method, this is the way to go: propagate the implicit evidence.
Related
Can someone explain me what the difference between these two approaches for typeclass instance derivation (specifically for Option[A])?
1.
trait MyTrait[A] {...}
object MyTrait extends LowPriority {
// instances for primitives
}
trait LowPriority extends LowestPriority {
final implicit def generic[A, H <: HList](
implicit gen: Generic.Aux[A, H],
h: Lazy[MyTrait[H]]
): MyTrait[A] = ???
final implicit val hnil: MyTrait[HNil] = ???
final implicit def product[H, T <: HList](
implicit h: Lazy[MyTrait[H]],
t: Lazy[MyTrait[T]]
): MyTrait[H :: T] = ???
}
// special instances for Options
trait LowestPriority {
implicit def genericOption[A, Repr <: HList](
implicit gen: Generic.Aux[A, Repr],
hEncoder: Lazy[MyTrait[Option[Repr]]]
): MyTrait[Option[A]] = ???
implicit val hnilOption: MyTrait[Option[HNil]] = ???
implicit def productOption1[H, T <: HList](
implicit
head: Lazy[MyTrait[Option[H]]],
tail: Lazy[MyTrait[Option[T]]],
notOption: H <:!< Option[Z] forSome { type Z }
): MyTrait[Option[H :: T]] = ???
implicit def product2[H, T <: HList](
implicit
head: Lazy[MyTrait[Option[H]]],
tail: Lazy[MyTrait[Option[T]]
): MyTrait[Option[Option[H] :: T]] = ???
}
trait MyTrait[A] {...}
object MyTrait extends LowPriority {
// instances for primitives
}
trait LowPriority {
// deriving instances for options from existing non-option instances
final implicit def forOption[A](implicit instance: MyTrait[A]): MyTrait[Option[A]] = ??? // <<<----
final implicit def generic[A, H <: HList](
implicit gen: Generic.Aux[A, H],
h: Lazy[MyTrait[H]]
): MyTrait[A] = ???
final implicit val hnil: MyTrait[HNil] = ???
final implicit def product[H, T <: HList](
implicit h: Lazy[MyTrait[H]],
t: Lazy[MyTrait[T]]
): MyTrait[H :: T] = ???
}
I tried both and they worked correctly, but i'm not sure that they will produce the same results for all cases (maybe i've missed something).
Do we really need LowestPriority instances for this?
Am i right if i would say that the first approach gives us just a little bit more flexibility?
I assuming that by "worked correctly" you mean "compiled" or "worked for some simple use case".
Both of your examples deal with generic product types, but not with generic sum types, so there is no risk that e.g. Option[A] could get derived using Some[A] :+: None :+: CNil, which would enforce some ambiguity. So (as far as I can tell) you could write the second version like:
trait MyTrait[A] {...}
object MyTrait extends LowPriority {
// instances for primitives
// deriving instances for options from existing non-option instances
final implicit def forOption[A](implicit instance: MyTrait[A]): MyTrait[Option[A]] = ???
}
trait LowPriority {
// <<<----
final implicit def hcons[A, H <: HList](
implicit gen: Generic.Aux[A, H],
h: Lazy[MyTrait[H]]
): MyTrait[A] = ???
final implicit val hnil: MyTrait[HNil] = ???
final implicit def product[H, T <: HList](
implicit h: Lazy[MyTrait[H]],
t: Lazy[MyTrait[T]]
): MyTrait[H :: T] = ???
}
and it would derive things correctly.
But how 1. and 2. differs?
In second version you can derive MyTrait[Option[A]] if you can derive for A, and you can derive for any A which is primitive/option/product - so Option[Option[String]], Option[String] and Option[SomeCaseClass] should all work. It should also work if this SomeCaseClass contains fields which are Options, or other case classes which are Options, etc.
Version 1. is slightly different:
at first you are looking for primitives
then you try to derive for a product (so e.g. Option would not be handled here)
then you do something weird:
genericOption assumes that you created a Option[Repr], and then I guess map it using Repr
in order to build that Repr you take Option[HNil] and prepend types inside Option using productOption, which would break if someone used Option as a field
so you "fix" that by prepending an Option in a special case product2
I guess, you tested that only against case classes, because the first version would not work for:
Option for primitives (Option[String], Option[Int] or whatever you defined as primitive)
nested options (Option[Option[String]])
options for custom defined types which are not case classes but have manually defined instances:
class MyCustomType
object MyCustomType {
implicit val myTrait: MyTrait[MyCustomType]
}
implicitly[Option[MyCustomType]]
For that reason any solution with implicit def forOption[A](implicit instance: MyTrait[A]): MyTrait[Option[A]] is simpler and more bulletproof.
Depending on what you put directly into companion low-priority implicits might be or might not be needed:
if you defined coproducts then manual support for e.g. Option, List, Either could conflict with shapeless derived ones
if you manually implemented MyTrait implicit for some type in its companion object then it would have the same priority as implicits directly in MyTrait - so if it could be derived using shapeless you could have conflicts
For that reason it makes sense to put shapeless implicits in LowPriorityImplicits but primitives, and manual codecs for List, Option, Either, etc directly in companion. That is, unless you defined some e.g. Option[String] implicits directly in companion which could clash with "Option[A] with implicit for A".
Since I don't know your exact use case I cannot tell for sure, but I would probably go with the seconds approach, or most likely with the one I implemented in the snippet above.
Actually it's hard to say without right hand sides and actual implementations.
From information you provided it doesn't follow that the two type classes behave equivalently.
For example in the 1st approach you consider some special cases, so theoretically it's possible that you redefine some general behavior in special case differently.
By the way, Option[A] is a coproduct of Some[A] and None.type (List[A] is a coproduct of scala.::[A] and Nil.type) and sometimes it's easier to derive a type class for coproducts than for Option[A] (or List[A]).
I'm trying to create an automatic adapter from two case classes which have different fields with different types and different order.
It works, sometimes. It's just very difficult to debug and know which implicit fails to be resolved.
When the compiler fails to find an specific adapter I have to start playing in test with each one of the needed implicits and check which one is failing and why. Is there a way to mark why a given implicit method was a candidate and stopped being when trying to resolve the nested implicits?
Sorry if it sounds confusing!
private implicit def fromRecordAdapter
[
Source, SourceFields <: HList, SourceRecord <: HList, Target, TargetFields <: HList, TargetRecord <: HList,
SelectedFields <: HList, AddedFields <: HList,
SourceTakenProduct <: HList, TargetProduct <: HList, CommonRecord <: HList, AddedProduct <: HList,
AddedRecord <: HList, UnorderedRecord <: HList
](
implicit
sourceRecord: LabelledGeneric.Aux[Source, SourceRecord]
, sourceFields: Keys.Aux[SourceRecord, SourceFields]
, targetRecord: LabelledGeneric.Aux[Target, TargetRecord]
, recordFields: Keys.Aux[TargetRecord, TargetFields]
, selectedFields: hlist.Intersection.Aux[SourceFields, TargetFields, SelectedFields]
, addedFields: hlist.Diff.Aux[TargetFields, SelectedFields, AddedFields]
, sourceTakenProduct: SelectAll.Aux[SourceRecord, SelectedFields, SourceTakenProduct]
, targetProduct: SelectAll.Aux[TargetRecord, SelectedFields, TargetProduct]
, addedProduct: SelectAll.Aux[TargetRecord, AddedFields, AddedProduct]
, sourceToTargetMapper: TypeMapper[TargetProduct, SourceTakenProduct]
, addedProductDefault: Lazy[DefaultValue[AddedProduct]]
, commonRecord: ZipWithKeys.Aux[SelectedFields, TargetProduct, CommonRecord]
, addedTagger: ZipWithKeys.Aux[AddedFields, AddedProduct, AddedRecord]
, prepend: Prepend.Aux[CommonRecord, AddedRecord, UnorderedRecord]
, align: hlist.Align[UnorderedRecord, TargetRecord]
): Adapter[Source, Target] = ...
In other words, I'd love to know in which parameter from that long list, the compiler stops and says, for example: "damn, there's no implicit for sourceToTargetMapper:TypeMapper[TargetProduct, SourceTakenProduct]"
That way I'd know where to start checking
You can try
scalacOptions += "-Xlog-implicits"
Doesn't compiler write that if you try to call fromRecordAdapter explicitly?
def foo(implicit i: Int, b: Boolean, s: String, l: Long): Unit = ()
implicit val int: Int = 1
implicit val bool: Boolean = true
foo
//Error: could not find implicit value for parameter s: String
//Error: not enough arguments for method foo: (implicit i: Int, implicit b: Boolean, implicit s: String, implicit l: Long)Unit.
//Unspecified value parameter s.
If I have a method such as:
def f[T: Generic, U: Generic](t: T): U
Generic[T].to(t) returns type Generic[T]#Repr which I assume is a type alias for some type of HList.
Is it possible to select members from the HList and build another HList which I can convince the compiler is of type Generic[U]#Repr which I can then use to create an instance of U using Generic[U].from(myNewHList)?
I have tried many approaches but seem to be going around in circles.
When doing stuff like this in Shapeless, the best place to look is in the shapeless.ops typeclasses. In this case, since you know your second class is a strict subset of your first, Intersection is sufficient to get what you want. You'll want to set this up as a type class, so that you can pass in your input and output types and let the compiler infer the intermediate stuff.
trait Converter[A,B] {
def convert(a: A): B
}
object Converter {
def apply[A,B](implicit converter: Converter[A,B]) = converter
implicit def genericConverter[A, B, ARepr <: HList, BRepr <: HList](
implicit
genA: Generic.Aux[A,ARepr],
genB: Generic.Aux[B,BRepr],
intersection: shapeless.ops.hlist.Intersection.Aux[ARepr,BRepr,BRepr]
): Converter[A,B] =
new Converter[A,B]{def convert(a: A): B = genB.from(intersection(genA.to(a)))}
}
This can be used as follows:
case class Foo(a: Int, b: Int, c: String)
case class Bar(a: Int, c: String)
val foo = Foo(1,2,"Three")
val bar: Bar = Converter[Foo, Bar].convert(foo)
Looking at ClassTag#runtimeClass, it has a return type of Class[_], i.e. a Class with, as I understand, a wildcard parameter.
I tried to implement a method: A => ClassTag[A]:
import scala.reflect._
scala> def f[A](x: A)(implicit ev: ClassTag[A]) = ev.runtimeClass
f: [A](x: A)(implicit ev: scala.reflect.ClassTag[A])Class[_]
But, the output of the def's definition is, as the docs show, Class[_].
Is it possible to change f such that its return type is Class[A]? If not, then why is it not possible?
Unless you change the signature of f, your only option is to cast the Class[_] to a Class[A].
There is literally only one method in the entire Scala standard library that returns a Class[A], and that is classOf. f[A] cannot be re-written to use classOf[A] since it is a special compiler method and is incompatible with generic type parameters that may not be classes. You would simply get an error:
scala> def f[A: ClassTag](x: A) = classOf[A]
<console>:10: error: class type required but A found
def f[A: ClassTag](x: A) = classOf[A]
^
The best you can get without casting is using x.getClass, but that will return a Class[_ <: A] (no ClassTag needed).
scala> def f[A](x: A): Class[_ <: A] = x.getClass
f: [A](x: A)Class[_ <: A]
scala> f(1)
res8: Class[_ <: Int] = class java.lang.Integer
scala> f(List(1, 2, 3))
res9: Class[_ <: List[Int]] = class scala.collection.immutable.$colon$colon
You might ask, why _ <: A?
The answer to that question is also the reason why your definition of f doesn't really make sense. If A is an Int, it makes sense to be able to return a Class[A] because Int is a class. But what if A is a List[Int]? List[Int] is not a class, it's a type. The class is List, but A != List, therefore we cannot return a Class[A] consistently. We can, however, have an upper-bound of A on the type parameter of Class.
Is it possible, using Shapeless, to extract a value of a specific type from a case class? So far, I can do this:
def fromCaseClass[T, R <: HList](value: T)(implicit ga: Generic.Aux[T, R]): R = {
ga.to(value)
}
Which then allows me to extract values procedurally:
scala> case class ServiceConfig(host: String, port: Int, secure: Boolean)
defined class ServiceConfig
scala> val instance = ServiceConfig("host", 80, true)
instance: ServiceConfig = ServiceConfig(host,80,true)
scala> fromCaseClass(instance).select[Boolean]
res10: Boolean = true
scala> fromCaseClass(instance).select[Int]
res11: Int = 80
However, when I try to write a function to do this, I'm getting tied up with implicits not found:
def getByType[C, X](value: C)(implicit ga: Generic.Aux[C, X]): X = {
fromCaseClass(value).select[X]
}
<console>:12: error: could not find implicit value for parameter ga: shapeless.Generic.Aux[C,R]
fromCaseClass(value).select[X]
Presumably I'm getting this because the compiler can't verify that my parameter is not a case class. Is there a way for me to do this?
I'm quite new to Shapeless, so I'm not entirely sure if I'm trying to do something crazy or if missing something simple.
Update
I feel I'm getting a bit closer. I can implement as so:
def newGetByType[C, H <: HList, R]
(value: C)
(implicit ga: Generic.Aux[C, H], selector: Selector[H, R]): R = {
ga.to(value).select[R]
}
And this allows me to select from a case class:
scala> val s: String = newGetByType(instance)
s: String = host
But this only seems to work for the first type in the case class:
scala> val i: Int = newGetByType(instance)
<console>:17: error: type mismatch;
found : String
required: Int
val i: Int = newGetByType(instance)
Am I on the right track?
You were getting close ...
The main problem with your newGetByType is that it doesn't give you any way to explicitly specify the type you're hoping to extract (and, as you've observed, typing the val on the LHS isn't sufficient to allow it to be inferred).
Why can't you explicitly specify the type to be extracted? Here's the definition again,
def getByType[S, C, L <: HList](value: C)
(implicit gen: Generic.Aux[C, L], sel: Selector[L, S]): S =
gen.to(value).select[S]
Ideally we'd like to be able to specify the type argument S, allow C to be inferred from the value argument, and L to be computed by implicit resolution from C. Unfortunately, however, Scala doesn't allow us to partially specify type arguments ... it's all or nothing.
So the trick to get this to work is to split the type parameter list into two: one which can be fully specified explicitly and one which can be fully inferred: this is a general technique, not one which is specific to shapeless.
We do this by moving the main part of the computation to an auxiliary class which is parametrized by the type we are going to supply explicitly,
class GetByType[S] {
def apply[C, L <: HList](value: C)
(implicit gen: Generic.Aux[C, L], sel: Selector[L, S]): S =
gen.to(value).select[S]
}
Notice that here we can now assume that S is known, and both of the type arguments to apply can be inferred. We finish up with the now trivial definition of getByType which just provides a place where the explicit type argument can go, and instantiates the auxiliary class,
def getByType[S] = new GetByType[S]
This gives you the result you want,
scala> import shapeless._, ops.hlist._
import ops.hlist._
scala> :paste
// Entering paste mode (ctrl-D to finish)
class GetByType[S] {
def apply[C, L <: HList](value: C)
(implicit gen: Generic.Aux[C, L], sel: Selector[L, S]): S =
gen.to(value).select[S]
}
// Exiting paste mode, now interpreting.
defined class GetByType
scala> def getByType[S] = new GetByType[S]
getByType: [S]=> GetByType[S]
scala> case class ServiceConfig(host: String, port: Int, secure: Boolean)
defined class ServiceConfig
scala> val instance = ServiceConfig("host", 80, true)
instance: ServiceConfig = ServiceConfig(host,80,true)
scala> getByType[String](instance)
res0: String = host
scala> getByType[Int](instance)
res1: Int = 80
scala> getByType[Boolean](instance)
res2: Boolean = true
I guess you have to pass ga explicitly with the call, because otherwise it will not be in scope for the called function (i.e. fromCaseClass):
def getByType[C, X](value: C)(implicit ga: Generic.Aux[C, X]): X = {
fromCaseClass(value)(ga).select[X]
}
Other way would be to bring this parameter into scope before fromCaseClass is called:
def getByType[C, X](value: C)(implicit ga: Generic.Aux[C, X]): X = {
val innerGa = ga
fromCaseClass(value).select[X]
}