One of my projects uses a mix of scala features that appear to not mix well together:
type classes, and shapeless automated type class instance derivation
implicit conversion (to add useful syntax to types that have type class instances)
default parameters, because even though they're usually a bad thing they're just too convenient here
The problem I'm running into is type class instance derivation fails if either:
default parameters are not explicitly specified
shapeless derivation uses Lazy
Here's the smallest possible amount of code I could write to reproduce the issue:
Show.scala
import shapeless._
trait Show[A] {
def show(a: A): String
}
object Show {
def from[A](f: A => String): Show[A] = new Show[A] {
override def show(a: A) = f(a)
}
implicit val intShow: Show[Int] = Show.from(_.toString)
implicit def singletonShow[A](implicit
sa: Show[A]
): Show[A :: HNil] = Show.from {
case (a :: HNil) => sa.show(a)
}
implicit def singletonCaseClassShow[A, H <: HList](implicit
gen: Generic.Aux[A, H],
sh: Lazy[Show[H]]
): Show[A] = Show.from {
a => sh.value.show(gen.to(a))
}
}
Run.scala
object Run extends App {
implicit class ShowOps[A](val a: A) extends AnyVal {
def show(header: String = "> ")(implicit sa: Show[A]): String =
header + sa.show(a)
}
case class Foo(i: Int)
println(Foo(12).show())
}
This fails to compile with the following error message:
Run.scala:10: could not find implicit value for parameter sa: Show[Run.Foo]
[error] println(Foo(12).show())
The compilation error is fixed by either:
explicitly passing a header parameter to show in Run.scala
removing the Lazy wrapper to the implicit Show[H] in Show.scala
I must admit I'm at a complete loss here. I'd love to understand what happens, and I'd love to know of a workaround if one exists.
Short answer:
If you move the context bound to the implicit class, it also works fine. You have to sacrifice the value class to do it, but I think it's also cleaner to tell the compiler up front that only As which have a Show will get enriched by it:
implicit class Show2Ops[A : Show](a: A) {
def show2(header: String = "> ") = header + implicitly[Show[A]].show(a)
}
println(Foo(12).show2())
Long theory:
Lazy does some interesting tricks, which are hard to follow. You didn't specifically ask about what Lazy is doing, but I was curious about it, since I use it all the time without being sure how it works. So I took a look at it. As near as I can tell, it goes something like this.
You have a case class with a recursive field:
case class A(first: Int, next: Option[A])
And assume you had another case in Show's companion for Option:
implicit def opt[A](implicit showA: Show[A]): Show[Option[A]] = Show.from {
case Some(a) => s"Some(${showA.show(a)})"
case None => "None"
}
And instead of singletonShow you had a real HNil case and an inductive case, as is typical:
implicit val hnil: Show[HNil] = Show.from(_ => "")
implicit def hcons[H, T <: HList](implicit
showH: Show[H],
showT: Show[T]
): Show[H :: T] = Show.from {
case h :: t => showH(h) + ", " + showT(t) // for example
}
And let's rename singletonCaseClassShow to genericShow because it's not just for singletons anymore.
Now let's say you didn't have the Lazy there in genericShow. When you try to summon a Show[A], the compiler goes to:
genericShow[A] with open implicit search for Show[A]
hcons[Int :: Option[A] :: HNil] with open implicit search for Show[A] and Show[Int :: Option[A] :: HNil
intShow with open implicit search for Show[A] and Show[Int] and Show[Option[A] :: HNil]
hcons[Option[A] :: HNil] with open implicit search for Show[A] and Show[Option[A] :: HNil]
opt[A] with open implicit search for Show[A] and Show[Option[A]] and Show[Option[A] :: HNil]
genericShow[A] with open implicit search for Show[A] and Show[Option[A]] and Show[Option[A] :: HNil]
Now it's pretty clear that there's a problem, because it's going to go back to #2 and happen all over again, never making any progress.
How Lazy overcomes this is by going into a macro at the time the compiler attempts to materialize an implicit instance of it. So when you use implicit showH: Lazy[Show[H]] in hcons instead of just Show[H], the compiler goes to that macro to find Lazy[Show[H]] instead of staying in your implicit Show cases.
The macro checks the open implicits (which macros helpfully have access to) and goes into its own implicit resolution algorithm that always fully resolves open implicits before continuing with finding the implicit instance of T (for Lazy[T]). If it comes to resolving an implicit that's already open, it substitutes a dummy tree (essentially telling the compiler "I got this, don't worry about it") that tracks the knotted dependencies so that the rest of the resolution can finish. And at the end, it cleans up the dummy trees (I can't quite figure out how this works; there's a surprising amount of code there and it's pretty complicated!)
So why does Lazy seem to mess up your default parameter situation? I think it's the confluence of a few things (only a hypothesis):
With your original ShowOps, calling .show on a value causes a it to be implicitly wrapped in ShowOps[A]. What is A going to be? Is it going to be Foo, AnyRef, Any? Is it going to be a unique single type? It's not exactly clear, because at that time there is no constraint on A and Scala doesn't know that your call to .show will actually constraint it (due to the context bound).
Without Lazy, this works out OK, because if Scala chooses the wrong A and .show doesn't typecheck, it will realize its mistake and back out of the A it chose.
With Lazy, there is a bunch of other logic going on, and it kind of tricks Scala into thinking that whatever A it chose is fine. But when it comes time to close the loop, it doesn't work out, and by that time it's too late to back out.
Somehow, the default parameter being unspecified influences Scala's initial choice for choosing A in ShowOps[A].
Related
I've tried the following:
type Params = String :: Int :: HNil
implicit val params: Params = "hello" :: 5 :: HNil
// Supposed to create an implicit for string and int if needed
implicit def meberImplicit[A](
implicit
params: Params,
selector: Selector[Params, A]
): A = params.select[A]
// Summoning a string
implicitly[String] // compile-time error
However, I'm getting a diverging implicit error:
diverging implicit expansion for type String
Am I missing something here? And maybe there already is a built-in or better way to achieve this?
The problem is that you are way too generic:
implicit def memberImplicit[A](
implicit // what you put here is irrelevant
): A = ...
With that you basically provided implicit for any value. This clashed with any other implicit you defined, as well as with any implicit parameter that you need to fetch.
But let's ask why compiler cannot prove that you just cannot provide the implicits that you pass into memberImplicit for bad cases, and so it won't consider it a viable alternative, ans so it would be able to prove that this branch of derivation should be cut (where you don't intent it), ambiguity is resolved, then cake.
Thing is, that the type you are returning is A. Which means that even if you added some constraint there like e.g. A =:!= Params - while normally it would work... you just provided all these implicits, so type constraints stopped working, and suddenly derivation for things like e.g. Selector[Params, String] have more that one way of being instantiated. In that situation virtually any implementation you'll try - as long as it returns A - will fail.
In order for things to work you HAVE TO constrain the output to be something that won't match everything - as a matter of the fact, the less it match the better. For instance create a separate type-class for extracting values from the HLists:
trait Extractable[A] { def extract(): A }
object Extractable {
implicit def extractHList[H <: HList, A](
implicit
h: H,
selector: Selector[H, A]
): Extractable[A] = () => selector(h)
}
def extract[A](implicit extractable: Extractable[A]): A = extractable.extract()
and then
extract[String] // "hello"
I am still trying to get my head around Shapeless (and, to a lesser extent, Scala!) and I have been writing some simple code to generate random instance data for case classes - predominantly based on the guides here: http://enear.github.io/2016/09/27/bits-of-shapeless-2/ (the example covers a JSON Writer implementation)
I have created a Generator[A] trait and created implicit implementations for simple types, and as per the example in the above link, I have also created implicit implementations to handle HList, HNil, Coproduct and CNil:
implicit def hnilGenerator = new Generator[HNil] {
override def generate(a: HNil) = HNil
}
implicit def hconsGenerator[H, T <: HList](implicit headGen: Generator[H], tailGen: Generator[T]) =
new Generator[H :: T] {
override def generate(a: H :: T) = headGen.generate(a.head) :: tailGen.generate(a.tail)
}
implicit def cnilGenerator: Generator[CNil] =
new Generator[CNil] {
override def generate(a: CNil): CNil = throw new RuntimeException("Invalid candidate configuration")
}
implicit def cconsGenerator[H, T <: Coproduct] =
new Generator[H :+: T] {
override def generate(a: H :+: T) = throw new RuntimeException("Invalid candidate configuration")
}
I can now use this code to generate a random instance based on a case class or a sealed trait:
it("should work with a case class to hlist") {
case class Test(x: IntGene, y: DoubleGene, z: BooleanGene)
val c = Generic[Test].to(Test(IntGene(), DoubleGene(), BooleanGene()))
generate(c)
}
it("what happens with sealed traits") {
sealed trait Shape
case class Square(width: Int, height: Int) extends Shape
case class Circle(radius: Int) extends Shape
val c = Generic[Shape].to(Circle(1))
generate(c)
}
Both of the above work no problem, however, if I try to make this a generic (as in parameter types) I get compilation errors not being able to find the necessary implicts:
it("should handle generics") {
case class GenericTest[A: Generic](x: A) {
def convert() = {
val c = Generic[A].to(x)
generate(c)
}
}
}
So from my understanding, because I have used the Generic context bound A, the compiler knows that is going to be available, so c must be some possible return from the call to(x) - Am I missing something in the implementation to handle that return type from the Generic shapeless call? Or have I wildly misunderstood something?
I am hoping this is possible and I have just missed something - is it that the compiler doesn't know what will be passed in (Im assuming not), or is there another possible type that needs to be handled implicitly from that to(x) call?
EDIT
Compile error added below - I'm really just trying to understand: Is it that there is some return case from the to(x) shapeless call that I have not catered for, or is it because the compiler doesn't have any idea what will be passed in and there are some types not catered for (e.g. I haven't added a Date generator implicit - and a case class could potentially have any type included? I was hoping that was not the case, and as the compiler knows nothing is actually being passed to the class/method it knows there are no issues?)
GeneratorSpec.scala:44: could not find implicit value for parameter gen: io.github.robhinds.genotype.Generator[GenericTest.this.evidence$1.Repr]
generate(c)
And my generate method is just a simple helper method that gets given the implicit Generator :
def generate[A](a: A)(implicit gen: Generator[A]) = gen.generate(a)
Your problem comes from the fact that Generic only converts a case class to a HList and a sealed trait to a Coproduct (not recursively).
So if you have a generic Generic, you have no information on what HList or Coproduct you are given, so, you cannot use your product and coproduct rules to find the wanted implicit. In some explicit case, you might have the same problem, so I will give you this as an example:
Let's say you have a case class architecture
case class Bottom(value: String)
case class Top(bot: Bottom, count: Int)
The implicit Generic[Top] will have type MyHList = Bottom :: Int :: HNil as output type, so you'll be asking for an implicit Generator[MyHList]. But since you don't have an implicit Generator[Bottom] in scope, you won't be able to use hconsgenerator.
In the generic case, it's even worse. The compiler can only infer HList for the output type of Generic[A] (and that's assuming you forget about Coproduct), so you need an implicit Generator[HList], which you cannot provide.
The solution is to give an implicit for constructs that have a generic that can itself be generated:
implicit def generic2generate[T, L <: HList](implicit generic: Generic.Aux[T, L], lGen: Generator[L]): Generator[T] = new Generator[T] {
def generate(c: T) = generic.from(lGen.generate(generic.to(c)))
}
EDIT
You can now follow the implicit resolution for our Top type:
We can have a Generator[Top] using last rule, if we have a Generic.Aux[Top, L] for some L, and a Generator[L].
The only Generic.Aux[Top, _] that exists implicitly is a Generic.Aux[Top, Bottom :: Int :: HNil], so we are reduced to finding a Generator[Top, Bottom :: Int :: HNil]
using the hcons rule three times, we are reduced to finding a Generator[Bottom], a Generator[Int] and a Generator[HNil].
Generator[Int] is given (I assume) and Generator[HNil] is the first rule, so we are reduced to finding a Generator[Bottom]
the only rule that can provide one, is once again the 3rd rule, so we must find a Generator[String :: HNil], since the only Generic available is a Generic.Aux[Bottom, String :: HNil].
using the hcons rule, we are down to finding a Generator[String], which can easily be provided.
This example shows different points:
first that it may take a long time when compiling to solve all these implicits (I only gave the main points of the proof, but the compiler has to try all possible branches)
second, that this resolution can only be done for a specific Generic, it cannot be inferred generically (although this might seem counter-intuitive); even if the human mind is able to tell that it will work for every Generic, the compiler cannot process it as such.
I think you are missing the Generator type bound.
it("should handle generics") {
case class GenericTest[A: Generic : Generator](x: A) {
def convert() = {
val c = Generic[A].to(x)
generate(c)
}
}
}
I am reading this code for a long time. I typed it into REPL and it works as well.
but I don't have any idea of what's going on here. Why and how does this even work!!!
import shapeless._
case class Size[L <: HList](get : Int)
object Size {
implicit val hnilSize = Size[HNil](0)
implicit def hconsSize[H, T <: HList](implicit tailSize: Size[T]) =
Size[H :: T](1 + tailSize.get)
def apply[L <: HList](l : L)(implicit size: Size[L]) : Int = size.get
}
Size(1 :: "Foo" :: true :: HNil)
Can someone explain this step by step and help me understand what is going on here.
Yeah, that's pretty thick stuff.
The mind-bender here is that hconsSize is recursive without actually being self referential.
Both apply and hconsSize pull in an implicit of type Size[X]. There are only two implicits that could fit that bill:
hnilSize, but only if X is type HNil
hconsSize itself
So apply pulls in the hconsSize implicit, which adds 1 to the stack and pulls in another hconsSize implicit (not necessarily in that order). This continues until we encounter an element of type HNil. Then the hnilSize implicit is pulled in, the get is zero, the stack is unrolled and all those 1's are added up.
Result: number of elements in the shapeless HList.
I had a neat idea (well, that's debatable, but let's say I had an idea) for making implicit dependency injection easier in Scala. The problem I have is that if you call any methods which require an implicit dependency, you must also decorate the calling method with the same dependency, all the way through until that concrete dependency is finally in scope. My goal was to be able to encode a trait as requiring a group of implicits at the time it's mixed in to a concrete class, so it could go about calling methods that require the implicits, but defer their definition to the implementor.
The obvious way to do this is with some kind of selftype a la this psuedo-scala:
object ThingDoer {
def getSomething(implicit foo: Foo): Int = ???
}
trait MyTrait { self: Requires[Foo and Bar and Bubba] =>
//this normally fails to compile unless doThing takes an implicit Foo
def doThing = ThingDoer.getSomething
}
After a few valiant attempts to actually implement a trait and[A,B] in order to get that nice syntax, I thought it would be smarter to start with shapeless and see if I could even get anywhere with that. I landed on something like this:
import shapeless._, ops.hlist._
trait Requires[L <: HList] {
def required: L
implicit def provide[T]:T = required.select[T]
}
object ThingDoer {
def needsInt(implicit i: Int) = i + 1
}
trait MyTrait { self: Requires[Int :: String :: HNil] =>
val foo = ThingDoer.needsInt
}
class MyImpl extends MyTrait with Requires[Int :: String :: HNil] {
def required = 10 :: "Hello" :: HNil
def showMe = println(foo)
}
I have to say, I was pretty excited when this actually compiled. But, it turns out that when you actually instantiate MyImpl, you get an infinite mutual recursion between MyImpl.provide and Required.provide.
The reason that I think it's due to some mistake I've made with shapeless is that when I step through, it's getting to that select[T] and then steps into HListOps (makes sense, since HListOps is what has the select[T] method) and then seems to bounce back into another call to Requires.provide.
My first thought was that it's attempting to get an implicit Selector[L,T] from provide, since provide doesn't explicitly guard against that. But,
The compiler should have realized that it wasn't going to get a Selector out of provide, and either chosen another candidate or failed to compile.
If I guard provide by requiring that it receive an implicit Selector[L,T] (in which case I could just apply the Selector to get the T) then it doesn't compile anymore due to diverging implicit expansion for type shapeless.ops.hlist.Selector[Int :: String :: HNil], which I don't really know how to go about addressing.
Aside from the fact that my idea is probably misguided to begin with, I'm curious to know how people typically go about debugging these kinds of mysterious, nitty-gritty things. Any pointers?
When I get confused about something related to implicits / type-level behaviour, I tend to find the reify technique useful:
scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._
scala> val required: HList = HNil
required: shapeless.HList = HNil
scala> reify { implicit def provide[T]:T = required.select[T] }
res3: reflect.runtime.universe.Expr[Unit] =
Expr[Unit]({
implicit def provide[T]: T = HList.hlistOps($read.required).select[T](provide);
()
})
At this point it's easy to see what's gone wrong - the compiler thinks provide can provide any arbitrary T (because that's what you've told it), so it just calls provide to get the required Selector[L, T]. At compile time it only resolves this once, so there is no diverging implicit, no confusion at compile time - only at run-time.
The diverging implicit expansion happens because the compiler looks for a Selector[Int :: String :: HNil], it thinks provide could give it one if given a Selector[Int :: String :: HNil, Selector[Int :: String :: HNil]], it thinks provide could give it one if given a Selector[Int :: String :: HNil, Selector[Int :: String :: HNil, Selector[Int :: String :: HNil]] and at some point it realises this is an infinite loop. Where/how are you expecting it to get the Selector it needs? I think your provide is misguided because it's too general. Try making the call to ThingDoer.needsInt with an explicit int work first before trying to make it all implicit.
This general approach does work - I've written applications that use it as a DI mechanism -though beware of quadratic compile times.
I just recently started learning scala and today I decided I wanted to write a CSV parser that would load nicely into case classes but store the data in rows (lists) of Shapeless's HList object so that I could get some exposure to type-level programming.
Here's what I have so far:
// LoadsCsv.scala
import shapeless._
import scala.collection.mutable
trait LoadsCsv[A, T <: HList] {
val rows: mutable.MutableList[T] = new mutable.MutableList[T]
def convert(t: T)(implicit gen: Generic.Aux[A, T]): A = gen.from(t)
def get(index: Int): A = {
convert(rows(index))
}
def load(file: String): Unit = {
val lines = io.Source.fromFile(file).getLines()
lines.foreach(line => rows += parse(line.split(",")))
}
def parse(line: Array[String]): T
}
And the object that's loading the data set:
// TennisData.scala
import shapeless._
case class TennisData(weather:String, low:Int, high:Int, windy:Boolean, play:Boolean)
object TennisData extends LoadsCsv[TennisData, String :: Int :: Int :: Boolean :: Boolean :: HNil] {
load("tennis.csv")
override def parse(line: Array[String]) = {
line(0) :: line(1).toInt :: line(2).toInt :: line(3).toBoolean :: line(4).toBoolean :: HNil
}
}
Things seem to be working alright until I added the get() with the conversion from the HList to the case class where I now get a compilation error. Why isn't the implicit getting loaded and what can I do to fix it or otherwise convert from the HList to the case class?
Error:(14, 17) could not find implicit value for parameter gen: shapeless.Generic.Aux[A,T]
return convert(rows(index))
^
I've been reading the shapeless documentation and it mentions that this area had been in flux between version 1 and 2, but I believe things should be working on my version of shapeless and scala so I suspect I've just done something incorrectly.
https://github.com/milessabin/shapeless/wiki/Migration-guide:-shapeless-1.2.4-to-2.0.0#iso-is-now-generic
For reference, I'm running scala 2.11.6 and shapeless 2.2.2
You're very close. The problem is that Scala isn't going to propagate implicit requirements up the call chain automatically for you. If you need a Generic[A, T] instance to call convert, then you'll have to make sure that one's in scope every time you call convert convert. If A and T are fixed (and are actually an case class-HList pair), Shapeless will generate one for you. In your get method, however, the compiler still knows nothing about A and T except that T is an HList, so you need to require the instance again in order to call convert:
def get(index: Int)(implicit gen: Generic.Aux[A, T]): A = convert(rows(index))
Everything should work just fine after this change.
Note that you could also require the instance at the trait level by adding an (abstract) method like the following:
implicit def genA: Generic.Aux[A, T]
Then any class implementing LoadsCsv could have an implicit val genA parameter (or could supply the instance in some other way).