Working around nasty Pattern Matcher bug - scala

I am defining a generic tree structure, i.e. one which can be extended so that for example branches and leaves contain additional values (I need this to add a name string for example).
So it looks like this:
trait TreeNodes {
val Node = Either
type Node[+B, +L] = Either[B, L]
val IsBranch = Left
type IsBranch[+B, +L] = Left[B, L]
val IsLeaf = Right
type IsLeaf[+B, +L] = Right[B, L]
}
object TreeLike extends TreeNodes {
trait BranchLike[Elem, B, L] {
type N = Node[B, L]
def iterator: Iterator[N]
}
trait LeafLike[Elem] {
def value: Elem
}
}
trait TreeLike[Elem, Repr] {
type Leaf <: TreeLike.LeafLike[Elem]
type Branch <: TreeLike.BranchLike[Elem, Branch, Leaf]
def root: Branch
}
Unfortunately, there is a pattern matcher bug:
def test[Elem, T <: TreeLike[Elem, T]](tree: T): Unit = {
import TreeLike.{IsLeaf, IsBranch}
def printLeaves(b: T#Branch): Unit = b.iterator.foreach {
case IsLeaf(l) => println(l.value)
case IsBranch(c) => printLeaves(c)
}
printLeaves(tree.root)
}
The error is as follows:
[error] during phase: patmat
[error] library version: version 2.10.3
[error] compiler version: version 2.10.3
...
[error] symbol definition: case val x1: b.N
[error] tpe: b.N
[error] symbol owners: value x1
[error] context owners: value x0$1 -> value $anonfun -> method printLeaves ->
method test -> object Voodoo -> package typerbug
...
[error] no-symbol does not have an owner
I suspect patmat has troubles with T#Branch somehow. Any ideas how to work around here?
I am also not 100% happy with wrapping leaves and branches in Either. This was necessary because the stuff got way out of hand when I tried to define a super type of LeafLike and BranchLike and figuring out how to correctly sub type that in implementations, and pattern matching broke done as well because I didn't figure out how to get correct extractors. So perhaps using Either is not that as a bad idea?

The type alias N is a "problem" (WTF).
trait BranchLike[Elem, B, L] {
def iterator: Iterator[Node[B, L]]
}
This makes it compile. Only that I am not very motivated to continue building this structure if it's about to collapse :-(

Related

Implicit not found for partially applied type

While this problem was caught in code using shapeless and kind-projector, this behavior could be reproduced without them.
Suppose I have simple typeclass for reifying typeclass instances with incomplete implementation (mirror of LiftAll).
sealed trait LiftAll1[F[_], In] {
type Out
def instances: Out
}
object LiftAll1 {
type Aux[F[_], In0, Out0] = LiftAll1[F, In0] {type Out = Out0}
implicit def unit[F[_]]: Aux[F, Unit, Unit] = new LiftAll1[F, Unit] {
type Out = Unit
def instances = Unit
}
}
And some very simple type class to test it
sealed class FirstIs[M, T]
object FirstIs {
implicit def firstIs[M, D]: FirstIs[M, (M, D)] = new FirstIs
}
Things are ok if I'll try to apply FirstIs partially via alias, and get instance via LiftAll1
type FirstIsInt[D] = FirstIs[Int, D]
implicitly[LiftAll1[FirstIsInt, Unit]]
But inlined partial type application leads to compilation error
implicitly[LiftAll1[({type lambda[x] = FirstIs[Int, x]})#lambda, Unit]]
//Error: could not find implicit value for parameter e: LiftAll1[[x]FirstIs[Int,x],Unit]
How partially applied typeclasses could be found in such situations?
As #Reactormonk suggested, the compiler was brought to its senses with following line in the build.sbt
scalacOptions += "-Ypartial-unification"
After that original piece of code, which is close to
import shapeless._, ops.hlist._
LiftAll[FirstIs[Int, ?], HNil]
was succesfully compiled
AFAIK problem was in scala compiler incapability to understand FirstIs[Int,_] as F[_]in supplied implicit def without direct type alias . Fortunately this was fixed in latest scala implementations.

ambiguous implicit values when using contravariant generic type

I've run into a problem with inferImplicitValue in a scala macro. I was playing around with a macro for play's json libary Format[T].
I could narrow it down to a problem how Writes[T] is sometimes implemented with OWrites[T]. Together with an explicit type declaration on
an implicit val, this led to the following compiler error.
[error] ambiguous implicit values:
[error] both value xm in object TestTest of type => OMaterializer[X]
[error] and value tm in object TestTest of type => Materializer[T]
[error] match expected type Materializer[X]
[error] one error found
[error] (root/compile:compile) Compilation failed
Let's look at the code (the SBT project can be found here, https://github.com/q42jaap/scala-macro-inferImplicitValue )
// models play json lib's Writes
trait Materializer[-T]
// models play json lib's OWrites
trait OMaterializer[T] extends Materializer[T]
trait T
case class X() extends T
object TestTest {
// The OMaterializer trait here is the second part of the problem
implicit val xm = new OMaterializer[X] {}
// the explicit `tm: Materializer[T]` type declaration here is first part of the problem
implicit val tm: Materializer[T] = Macro.genMaterializer[T, X]
}
object Macro {
def genMaterializer[T, M]: Materializer[T] = macro MacroImpl.genMaterializer[T, M]
}
object MacroImpl {
def genMaterializer[T: c.WeakTypeTag, M: c.WeakTypeTag](c: blackbox.Context): c.Expr[Materializer[T]] = {
val tMaterializerTpe = c.universe.appliedType(c.typeOf[Materializer[_]], c.weakTypeOf[M])
c.inferImplicitValue(tMaterializerTpe)
c.universe.reify {
new Materializer[T] {}
}
}
}
Note the explicit type declaration for tm, removing it, fixes the issue. When xm is Materializer[X] instead of OMaterializer[X], it also works.
inferImplicitValue considers both tm and xm when looking for a Materializer[X]. When xm is of the type Materializer[X] and tm has the type
Materializer[T] the inferer prefers xm over tm, because it's an exact match. But when xm is OMaterializer[X] the compiler cannot decide anymore which one
is better and throws an error.
As I said removing the explicit type declaration from tm fixes the problem, because at the time when the macro is executed only xm's type is known.
Can I solve this problem inferImplicitValue has? The silent option is already true (by default).
In my real use case, I have multiple implementations of T (X, Y, Z) and pass then with a union type (like reactivemongo does) to the Macro:
genMaterializer[T, Union[X \/ Y \/ Z]]
So I have to use the inferImplicitValue to find a Materializer for X, Y and Z.
Note that I have further simplified this case to
object ThisDoesntWorkToo {
implicit val xm = new OMaterializer[X] {}
implicit val tm: Materializer[T] = withoutMacro[X]
def withoutMacro[A](implicit m: Materializer[A]): Materializer[A] = m
}
which doesn't use macros, but has the same compiler error:
[error] TestTest.scala:15: ambiguous implicit values:
[error] both value xm in object ThisWorks of type => OMaterializer[X]
[error] and value tm in object ThisWorks of type => Materializer[T]
[error] match expected type Materializer[X]
[error] implicit val tm: Materializer[T] = withoutMacro[X]
This simplifies the case here, but still leaves me with the problem that a implementation of an implicit val can refer to itself.
The easy and obvious in the latter case is to explicitly provide the implicit value, but as argumented in the final version of the macro I need to use inferImplicitValue
because I have a list of types for which I have to find a Materializer.
I'm not sure what you mean by "fixes" or "it works", but this is just overload resolution at work.
When both are Materializer, tm wins because Mat[T] <:< Mat[X].
If the use case is to introduce the implicit tm as you show, in that scope, but pick up xm implicitly, then this is the only trick I could come up with:
implicit val tm: Materializer[T] = {
val tm = 0
Macro.genMaterializer[T, X]
}
which works by simply eliminating the implicit tm from the explicit scope.
Maybe an ugly macro could generate that block automatically, from which the real macro is expanded. That breaks locality.
Usually, you eliminate an implicit by making it ambiguous, but you want the implicit in this scope. So shadowing removes it from the nested scope only.
This doesn't help, but is natural:
object X {
implicit val xm: OMaterializer[X] = new OMaterializer[X] {}
}

Shapeless: Checking Type Constraints of Polymorphic functions

I'm working on a small library for economic models that check the Units of the entities, using Types, e.g. instead of val apples = 2.0 we write val apples = GoodsAmount[KG, Apples](2.0). For creating bundle of goods, I trying to use HLists from the shapeless library. This works fine, but in some cases I can not be as generic code as I prefer. See e.g. the following problem.
I start with a simple code that explain what I want to lift into shapeless. We create two classes, on that represent Km, the other Miles. It should be allowed to add Km classes, but not miles. That I use a abstract type T is mainly motivated be our more complex library. And the indirect call to the '+' function is just because we need something similar in the shapeless case behind.
trait Foo {
type T
val v: Double
def +[B <: Foo](other: B)(implicit ev: this.T =:= other.T) = v + other.v
}
trait _Km
trait _Miles
case class Km(v: Double) extends Foo { type T = _Km }
case class Miles(v: Double) extends Foo { type T = _Miles }
object ExampleSimple extends App {
def add[A <: Foo, B <: Foo](a: A, b: B)(implicit ev: a.T =:= b.T) = { a + b }
add(Km(1), Km(2))
// add(Km(1), Miles(2)) /* does not compile as intended */
}
This works as intended. But it's necessary to have the Type Contraint check on the 'add' function. My attempt to extend this to HLists looks like this:
object ExampleShapeless extends App {
import shapeless._
val l1 = Km(1) :: Km(2) :: HNil
val l2 = Km(4) :: Km(3) :: HNil
object add extends Poly1 {
implicit def caseTuple[A <: Foo] = at[(A,A)] { case (a, b) => a + b }
}
(l1 zip l2).map(add)
}
But this generate the following error message (using Scala 2.10.2):
[error] /home/fuerst/gitg3m/code/types/src/main/scala/lagom_d/extract.scala:50: Cannot prove that a.T =:= b.T.
[error] implicit def caseTuple[A <: Foo] = at[(A,A)] { case (a: Foo, b) => a + b }
[error] ^
[error] /home/fuerst/gitg3m/code/types/src/main/scala/lagom_d/extract.scala:54: could not find implicit value for parameter mapper: shapeless.Mapper[ExampleShapeless.add.type,shapeless.::[(Km, Km),shapeless.::[(Km, Km),shapeless.HNil]]]
[error] (l1 zip l2).map(add)
The first error should be fixed, in the case that I could add a Type Constraint to the caseTuple function, but to be honest, I have not understood how the at function is working and where I could add the implicit evidence parameter. And I'm also don't know, what I must do, so that the Mapper would find his implicit value.
A less generic version, where I replase the caseTuple function with
implicit def caseTuple = at[(Km,Km)] { case (a, b) => a + b }
works fine, but would need to write a lot of redundant code (okay, this solution would be still better as our current solution using Tuples). Can somebody give me a hint how I can solve this problem?
Thanks,
Klinke
You can require the type members to match by adding a type parameter to the case:
object add extends Poly1 {
implicit def caseTuple[_T, A <: Foo { type T = _T }] = at[(A, A)] {
case (a, b) => a + b
}
}
Or you could use an existential type, since you only really care that they're the same:
object add extends Poly1 {
implicit def caseTuple[A <: Foo { type T = _T } forSome { type _T }] =
at[(A, A)] {
case (a, b) => a + b
}
}
Either version will provide the behavior you want.

Pass type information at runtime

I have a DSL and some runtime code. The problem is I got somewhere at runtime:
val clazz: Class[_ <: java.io.Serializable] = classOf[java.lang.String]
val value: java.io.Serializable = "abc"
and I have a class
class MyWrapper[T <: java.io.Serializable](val data: T)(implicit m: Manifest[T]) {
override def toString = m.runtimeClass
}
val wrapper = new MyWrapper(value)
The problem is I need to return java.lang.String from a call of toString. But I got java.io.Serializable. Unfortunately I am neither able to create fixed pattern matching for each java.io.Serializable subtype (this would be crazy) nor to create MyWrapper explicit with new MyWrapper[String](value). I don't know the type of value, maybe it is a subtype of Serializable.
Is there some way to pass type/manifest value at runtime if I know that value type is equal to variable clazz?
Update (solution from Régis Jean-Gilles don't work). REPL test:
val clazz: Class[_ <: java.io.Serializable] = classOf[java.lang.String]
val value: java.io.Serializable = "abc"
class MyWrapper[T <: java.io.Serializable](val data: T)(implicit m: Manifest[T]) {
override def toString = m.runtimeClass.getName
}
val wrapper = new MyWrapper(value)
//val wrapper = new MyWrapper(value)(ClassManifest.fromClass(clazz).asInstanceOf[ClassTypeManifest[java.io.Serializable]])
//val wrapper = new MyWrapper(value)(ClassManifest.fromClass(clazz))
System.err.println(wrapper.toString)
I got an error, if I tried to pass manifest explicit:
scala> :load test.scala
Loading test.scala...
clazz: Class[_ <: java.io.Serializable] = class java.lang.String
value: java.io.Serializable = abc
defined class MyWrapper
<console>:10: error: type mismatch;
found : scala.reflect.ClassManifest[_$1] where type _$1 <: java.io.Serializable
(which expands to) scala.reflect.ClassTag[_$1]
required: Manifest[java.io.Serializable]
val wrapper = new MyWrapper(value)(ClassManifest.fromClass(clazz))
^
<console>:8: error: not found: value wrapper
System.err.println(wrapper.toString)
Also I am unable to cast manifest explicit.
There is more strange error when I try to compile my application -
[error] found : scala.reflect.ClassManifest[(some other)_0(in method setProperty)]
[error] (which expands to) scala.reflect.ClassTag[(some other)_0(in method setProperty)]
[error] required: Manifest[_0(in method setProperty)]
[error] new Value.Static(default, Context.virtual(element))(ClassManifest.fromClass(elementProperty.typeClass)))
IMHO Régis Jean-Gilles very very close to solution. How to make it work with Scala 2.10?
If I understand correctly, you are using manifests to work around type erasure but at a specific point all you have is a Class[_] so you need to convert it back to a manifest. Correct?
If so, you can use ClassManifest.fromClass, and then explicitly pass it as the implicit value m.
val wrapper = new MyWrapper(value)(Manifest.classType(clazz))
You should probably abstract it away:
object MyWrapper {
def fromRuntimeType[T <: java.io.Serializable]( value: T ): MyWrapper[T] = {
new MyWrapper(value)(Manifest.classType(value.getClass))
}
}
Keep in mind though that because you only have a Class instance in the first place, you are at the mercy of type erasure again. This means that if the class (that you need to get a manifest for) is generic, you won't have any type parameter information in the manifest returned by ClassManifest.fromClass.
Wouldn't
override def toString = data.getClass.getName
already work for you? That yields java.lang.String.

Scala: Equivalence of path-dependent types

How do I get around with equivalence of two path-dependent types that I know are the same but the compiler does not?
Using Scala 2.10.0 M7 I am trying to convert an AST from one universe to another.
case class MacroBridge(context: Context) {
def toMacroTree(tree: treehugger.forest.Tree): context.universe.Tree = ???
def fromMacroTree(tree: context.universe.Tree): treehugger.forest.Tree = ???
}
Within a macro implementation, I can use it as:
val bridge = treehugger.MacroBridge(c)
def fromMacroTree(tree: c.universe.Tree): Tree = bridge.fromMacroTree(tree)
However, this results to a compiler error:
[error] /scalamacros-getting-started/library/Macros.scala:21: type mismatch;
[error] found : c.universe.Tree
[error] required: bridge.context.universe.Tree
[error] possible cause: missing arguments for method or constructor
[error] def fromMacroTree(tree: c.universe.Tree): Tree = bridge.fromMacroTree(tree)
In the above code c is clearly the same value as bridge.context, but maybe because it's a value type checker cannot check it. Putting generalized type constraint did not help:
def fromMacroTree[A](tree: A)(implicit ev: A =:= context.universe.Tree): Tree =
In the macro this still resulted to an error:
[error] /scalamacros-getting-started/library/Macros.scala:21: Cannot prove that c.universe.Tree =:= bridge.context.universe.Tree.
[error] def fromMacroTree(tree: c.universe.Tree): Tree = bridge.fromMacroTree(tree)
I need the access to context.universe so I can get to other dependent types like TermName. Is there a better work around besides casting?:
def fromMacroTree(tree: c.universe.Tree): Tree =
bridge.fromMacroTree(tree.asInstanceOf[bridge.context.universe.Tree])
I could the following make to work:
case class MacroBridge[C <: Context](context: C) {
def fromMacroTree(tree: context.universe.Tree): context.universe.Tree = ???
}
trait MB {
def meth(c: Context) {
val bridge = MacroBridge[c.type](c)
def fromMacroTree(tree: c.universe.Tree): c.universe.Tree =
bridge.fromMacroTree(tree)
}
}
I had nearly the same problem some time ago.