import shapeless._; import labelled._;
object CreateField {
type OptionalField[K <: Symbol, T] = FieldType[K, Option[T]]
def pure[K <: Symbol, T](key: Witness.Aux[K], v: Option[T]): OptionalField[K, T] = {
field[K](v)
}
}
The complain was
found : v.type (with underlying type Option[T]) [error] required:
shapeless.labelled.KeyTag[K,Option[T]] with Option[T]
However, if you specify the type for field[K].apply[Option[T]] it compiles, or if you simply first set it to a val and return that val, that is the following method body compiles:
def pure[K <: Symbol, T](key: Witness.Aux[K], v: Option[T]): OptionalField[K, T] = {
val f = field[K](v)
f
}
}
If you don't use the OptionalField type alias, it also compiles.
Is this a ScalaC bug or it's just the way scalaC infers type is somehow incompatible with this field method from shapeless?
Related
I want to derive instances of type classes from unary case classes. But when i try to implicitly derive it i always get an error message. If i derive it explicitly using implicit method - it works. I'm not sure, but maybe the reason is that i missed some implicit types in my function
import shapeless._
import scala.reflect.ClassTag
import scala.reflect.runtime.universe.TypeTag
sealed trait Foo[A] {
def hello(): Unit
}
object Foo {
def apply[A](implicit foo: Foo[A]): foo.type = foo
def instance[A](implicit tag: ClassTag[A]): Foo[A] = new Foo[A] {
override def hello(): Unit = println(s"Hello from ${tag.runtimeClass.getName}")
}
}
trait Instances extends LowestPriority {
implicit val intHelloInstance: Foo[Int] = Foo.instance[Int]
}
trait LowestPriority {
implicit def derive[A: TypeTag, L <: HList, H](
implicit gen: Generic.Aux[A, L],
H: Lazy[Foo[H]],
isUnary: (H :: HNil) =:= L
): Foo[A] =
new Foo[A] {
override def hello(): Unit = {
print(s"Derived: ")
H.value.hello()
}
}
}
object T extends Instances {
case class A(a: Int)
def main(args: Array[String]): Unit = {
intHelloInstance.hello()
// val a: Foo[A] = derive[A, Int :: HNil, Int] // this works
// a.hello()
Foo[A].hello() // error
}
}
From logs:
Information:(45, 8) shapeless.this.Generic.materialize is not a valid
implicit value for shapeless.Generic.Aux[H,L] because:
hasMatchingSymbol reported error: H is not a case class, case
class-like, a sealed trait or Unit
Foo[A].hello()
How can i fix it?
This is one of the cases when behavior depends on... the order of implicits to resolve.
If you modify signature to:
implicit def derive[A, L <: HList, H](
implicit gen: Generic.Aux[A, L],
isUnary: (H :: HNil) =:= L, // swapped
H: Lazy[Foo[H]] // with this
): Foo[A] = ...
compiler will:
try to find some HList L that could be paired with A
then prove that L equal to some H :: HNil figuring out H in the process
finally using that H to fetch Lazy[Foo[H]]
and you will successfully compile Foo[A].hello().
When these two last argument are swapped to what you have in your question, compiler has to
assume some H (which in our test case most likely WON"T be Int)
then forcefully try to adjust L to match it
then go back to Generic which now is forced to prove that A is representable by some H :: HNil where H is most likely not Int and failing to do it but with a misguiding error information
This is one of these cases that shows that shapeless based derivation is sometimes tricky, and also here it shows that shapeless authors assumed in macros that the most likely cause of macro expansion failure is that A was not case class, while as we just saw it might be also compiler forcing some impossible proof because type inference got things wrong because we resolved them in wrong order.
I'm working with Slick's GetResult typeclass and wanted to use Shapeless to derive instances of GetResult[Option[(A, B, C...)]]
What I want:
Given an implicit GetResult[Option[A]], GetResult[Option[B]], ...,
implicitly generate a GetResult[Option[(A, B, ...)]]
What I tried
trait CanGetOption[T] {
def getOption: GetResult[Option[T]]
}
object CanGetOption {
// convenience implicit resolver
def apply[T](implicit canGetOption: CanGetOption[T]): CanGetOption[T] = canGetOption
// base case: HNil
implicit val getHNilOption: CanGetOption[HNil] = from(GetResult { _ => Some(HNil) })
// recursion case: H :: Tail
implicit def getHConsOption[H, Tail <: HList](
implicit getHeadOption: GetResult[Option[H]],
canGetTailOption: CanGetOption[Tail]
): CanGetOption[H :: Tail] = from(GetResult[Option[H :: Tail]] { r =>
val headOpt = getHeadOption(r)
val tailOpt = canGetTailOption.getOption(r)
for(head <- headOpt; tail <- tailOpt) yield head :: tail
})
// generic case: A, given a A <-> Repr conversion
// I also tried moving this into a "LowPriorityImplicits" thing, just in case
implicit def getGenericOption[A, Repr <: HList](
implicit gen: Generic.Aux[A, Repr],
getReprOpt: CanGetOption[Repr]
): CanGetOption[A] = from(GetResult { r =>
val reprOpt = getReprOpt.getOption(r)
reprOpt.map(gen.from)
})
}
implicit def resolveOptionGetter[T: CanGetOption]: GetResult[Option[T]] =
CanGetOption[T].getOption
Problem:
When I've imported the above, the resolveOptionGetter doesn't seem to be considered when searching for implicits:
scala> implicitly[GetResult[Option[(Int, Int)]]]
<console>:19: error: could not find implicit value for parameter e: scala.slick.jdbc.GetResult[Option[(Int, Int)]]
implicitly[GetResult[Option[(Int, Int)]]]
^
scala> resolveOptionGetter[(Int, Int)]
res1: scala.slick.jdbc.GetResult[Option[(Int, Int)]] = <function1>
Why can't the compiler find resolveOptionGetter in the implicit search? What can I do to help it?
The thing is that slick.jdbc.GetResult is covariant. If it were invariant, types would be inferred correctly and implicits would be resolved.
A workaround is hiding covariant slick.jdbc.GetResult with custom invariant type alias GetResult. Remove import slick.jdbc.GetResult and write in your source file
type GetResult[T] = slick.jdbc.GetResult[T]
object GetResult {
def apply[T](implicit f: PositionedResult => T): GetResult[T] = slick.jdbc.GetResult.apply
}
Now implicitly[GetResult[Option[(Int, Int)]]] compiles. Tested in Scala 2.12.7 + Shapeless 2.3.3 + Slick 3.2.3.
Variance often makes troubles for implicit resolution:
https://github.com/scala/bug/issues/10099
https://github.com/locationtech/geotrellis/issues/1292
Implicit resolution with covariance
Is there a way to get the compiler to somehow consider type aliases when looking for implicit evidence?
Here is an example of problem I am trying to solve:
// Third party library
class Foo[T, P]
class FooOps[FTP, T] {
def apply[F[_, _], P](t: T)(implicit ev: F[T, P] =:= FTP): FTP = ???
}
type StringFoo = Foo[String, Boolean]
object StringFoo extends FooOps[StringFoo, String]
StringFoo("hello")
// Attempt to wrap the third party type but have the same ops
class WrappedFoo[FTP](val foo: FTP)
object WrappedFoo {
type F[T, P] = WrappedFoo[Foo[T, P]]
}
type WrappedStringFoo = WrappedFoo[StringFoo]
object WrappedStringFoo extends FooOps[WrappedStringFoo, String]
WrappedStringFoo("hello") // Cannot prove that F[String, P] =:= WrappedStringFoo
WrappedStringFoo[WrappedFoo.F, Boolean]("hello”) // This works
I don't quite understand how the compiler infers the types in:
StringFoo("hello")
Does it somehow use the available implicits to choose a value for F[_, _]? I always thought that it had to work out the types first.
However it works for StringFoo it doesn't work for WrappedStringFoo. Likely since the number of type parameters is different.
How can I get:
WrappedStringFoo("hello")
to compile without specifying the types explicitly?
Try to add necessary implicit to scope:
import scala.language.higherKinds
class Foo[T, P]
class FooOps[FTP, T] {
def apply[F[_, _], P](t: T)(implicit ev: F[T, P] =:= FTP): FTP = ???
}
type StringFoo = Foo[String, Boolean]
object StringFoo extends FooOps[StringFoo, String]
class WrappedFoo[FTP](val foo: FTP)
object WrappedFoo {
type F[T, P] = WrappedFoo[Foo[T, P]]
//implicit val ev0: WrappedFoo.F[String, Boolean] =:= WrappedStringFoo = ???
implicit val ev0: WrappedFoo.F[String, Boolean] =:= WrappedStringFoo =
null.asInstanceOf[WrappedFoo.F[String, Boolean] =:= WrappedStringFoo]
}
type WrappedStringFoo = WrappedFoo[StringFoo]
object WrappedStringFoo extends FooOps[WrappedStringFoo, String]
WrappedStringFoo("hello")
When you do StringFoo("hello") compiler solves equation F[String, P] = Foo[String, Boolean] and it's smart enough to deduce P = Boolean, F = Foo. But when you do WrappedStringFoo("hello") compiler has to solve equation F[String, P] = WrappedFoo[Foo[String, Boolean]] and algorithms it uses are not smart enough to deduce P = Boolean, F = ({ type λ[A, B] = WrappedFoo[Foo[A, B]] })#λ i.e. WrappedFoo.F (and possibly such equations can't be solved in general if they are advanced enough). So you should provide a hint. Either specifying type parameters explicitly or providing necessary implicit evidence.
Resolving implicits and type inference make impact on each other. You can read section 4.4.3 of Eugene Burmako's thesis.
I'm trying to parametrize a method that needs to work on a generic type A for which a LabelledGeneric can be retrieved. Here's the naive approach
case class Foo(bar: String, baz: Boolean)
def params[A](a: A) = {
val lbl = LabelledGeneric[A]
val keys = Keys[lbl.Repr].apply
...
}
val myThingy = params(Foo)
Of course, the underlying macro complains. It doesn't know enough about A:
type A is not a class or trait
So, I tried to have the LabelledGeneric inferred
def params[A](a: A)(implicit lbl: LabelledGeneric[A]) = {
val keys = Keys[lbl.Repr].apply
...
}
this seems to work, but the Repr type is not known to be an HList anymore
type arguments [lbl.Repr] do not conform to method apply's type parameter bounds [L <: shapeless.HList]
Ok, let's try to be more precise
def params[A, Repr <: HList](a: A)(implicit lbl: LabelledGeneric.Aux[A, Repr]) = {
val keys = Keys[lbl.Repr].apply
...
}
Now, Repr is definitely an HList, but still Keys cannot resolve its implicits
could not find implicit value for parameter values: shapeless.ops.record.Values[lbl.Repr]
Final attempt, let's try to have everything I need computed implicitly
def params[A, Repr <: HList](a: A)(implicit
lbl: LabelledGeneric.Aux[A, Repr],
kk: Keys[Repr]
) = {
val keys = kk.apply
...
}
Still no luck, apparently the first implicit cannot be resolved at call site
could not find implicit value for parameter lbl: shapeless.LabelledGeneric.Aux[example.Main.Foo.type,Repr]
[error] params(Foo)
Clearly all of this machinery works, when dealing directly with the specific type, e.g.
val lbl = LabelledGeneric[Foo]
val keys = Keys[lbl.Repr].apply
// no problem
I'm clearly missing the needed set of refinements on my type in the method signature, but I can get my head around what's going on here. Any idea?
The last variant with everything computed implicitly works for me,
scala> import shapeless._, ops.record._
import shapeless._
import ops.record._
scala> :paste
// Entering paste mode (ctrl-D to finish)
def params[A, Repr <: HList](a: A)
(implicit lbl: LabelledGeneric.Aux[A, Repr], kk: Keys[Repr]) = {
val keys = kk.apply
keys
}
// Exiting paste mode, now interpreting.
params: ...
scala> case class Foo(bar: String, baz: Boolean)
defined class Foo
scala> params(foo)
res0: ... = 'bar :: 'baz :: HNil
(result types elided for readability).
Suppose I've got a type class that proves that all the types in a Shapeless coproduct are singleton types:
import shapeless._
trait AllSingletons[A, C <: Coproduct] {
def values: List[A]
}
object AllSingletons {
implicit def cnilSingletons[A]: AllSingletons[A, CNil] =
new AllSingletons[A, CNil] {
def values = Nil
}
implicit def coproductSingletons[A, H <: A, T <: Coproduct](implicit
tsc: AllSingletons[A, T],
witness: Witness.Aux[H]
): AllSingletons[A, H :+: T] =
new AllSingletons[A, H :+: T] {
def values = witness.value :: tsc.values
}
}
We can show that it works with a simple ADT:
sealed trait Foo
case object Bar extends Foo
case object Baz extends Foo
And then:
scala> implicitly[AllSingletons[Foo, Bar.type :+: Baz.type :+: CNil]].values
res0: List[Foo] = List(Bar, Baz)
Now we want to combine this with Shapeless's Generic mechanism that'll give us a coproduct representation of our ADT:
trait EnumerableAdt[A] {
def values: Set[A]
}
object EnumerableAdt {
implicit def fromAllSingletons[A, C <: Coproduct](implicit
gen: Generic.Aux[A, C],
singletons: AllSingletons[A, C]
): EnumerableAdt[A] =
new EnumerableAdt[A] {
def values = singletons.values.toSet
}
}
I'd expect implicitly[EnumerableAdt[Foo]] to work, but it doesn't. We can use -Xlog-implicits to get some information about why:
<console>:17: shapeless.this.Witness.apply is not a valid implicit value for
shapeless.Witness.Aux[Baz.type] because:
Type argument Baz.type is not a singleton type
implicitly[EnumerableAdt[Foo]]
^
<console>:17: this.AllSingletons.coproductSingletons is not a valid implicit
value for AllSingletons[Foo,shapeless.:+:[Baz.type,shapeless.CNil]] because:
hasMatchingSymbol reported error: could not find implicit value for parameter
witness: shapeless.Witness.Aux[Baz.type]
implicitly[EnumerableAdt[Foo]]
^
<console>:17: this.AllSingletons.coproductSingletons is not a valid implicit
value for AllSingletons[Foo,this.Repr] because:
hasMatchingSymbol reported error: could not find implicit value for parameter
tsc: AllSingletons[Foo,shapeless.:+:[Baz.type,shapeless.CNil]]
implicitly[EnumerableAdt[Foo]]
^
<console>:17: this.EnumerableAdt.fromAllSingletons is not a valid implicit
value for EnumerableAdt[Foo] because:
hasMatchingSymbol reported error: could not find implicit value for parameter
singletons: AllSingletons[Foo,C]
implicitly[EnumerableAdt[Foo]]
^
<console>:17: error: could not find implicit value for parameter e:
EnumerableAdt[Foo]
implicitly[EnumerableAdt[Foo]]
^
Baz.type obviously is a singleton type, though. We can try putting the Witness instances in scope manually just for fun:
implicit val barSingleton = Witness[Bar.type]
implicit val bazSingleton = Witness[Baz.type]
And somehow now it works:
scala> implicitly[EnumerableAdt[Foo]].values
res1: Set[Foo] = Set(Bar, Baz)
I don't understand why these instances would work in this context while the ones generated by the Witness.apply macro method (which we used to create them) don't. What's going on here? Is there a convenient workaround that doesn't require us to enumerate the constructors manually?
This works as written as of the most recent shapeless 2.1.0-SNAPSHOT.