Scala: type inference issue - scala

I have:
sealed trait Par[A]{def foo = ???}
case class Unit[A](v: () => A) extends Par[A]
case class Map2[L, R, A](parLeft: Par[L],
parRight: Par[R],
map: (L, R) => A) extends Par[A]
my problem is that when I pattern match on p:Par[A] to do something like this:
def getSequentially: A = this match {
case Par.Unit(f) => f()
case Par.Map2(a, b, f) => f(a.getSequentially, b.getSequentially)
}
L and R are inferred to be Any in Intellij's type inspector and getSequentially calls are highlighted in red, warning: type mismatch, expected Nothing, actual Any, since f is expected to be of type: (Nothing, Nothing) => A. Although it actually runs and compiles.
I think I understand what the problem is and I should be able to solve it with existential types in the definition of Map2. Only problem is that the map parameter has a dependent type, so I don't know how to do that. Maybe I should do a variation of the AUX pattern?
My question is, firstly why it compiles and secondly, if there is a way of restructuring the type dependency so that it no longer issues a warning.

If you want to have existentials you can use typed patterns:
sealed trait Par[A]{
def getSequentially: A = this match {
case x: Par.Unit[A] => x.v()
case x: Par.Map2[_, _, A] => x.map(x.parLeft.getSequentially, x.parRight.getSequentially)
}
}
object Par {
case class Unit[A](v: () => A) extends Par[A]
case class Map2[L, R, A](parLeft: Par[L],
parRight: Par[R],
map: (L, R) => A) extends Par[A]
}
IntelliJ seems not to highlight this.

Related

A way to avoid asInstanceOf in Scala

I have this hierarchy of traits and classes in Scala:
trait A
trait B[T] extends A {
def v: T
}
case class C(v:Int) extends B[Int]
case class D(v:String) extends B[String]
val l:List[A] = C(1) :: D("a") :: Nil
l.foreach(t => println(t.asInstanceOf[B[_]].v))
I cannot change the type hierarchy or the type of the list.
Is there a better way to avoid the asInstanceOf[B[_]] statement?
You might try pattern matching.
l.collect{case x :B[_] => println(x.v)}
You might try something like this:
for (x <- l.view; y <- Some(x).collect { case b: B[_] => b }) println(y.v)
It doesn't require any isInstanceOf or asInstanceOf, and never crashes, even if your list contains As that aren't B[_]s. It also doesn't create any lengthy lists as intermediate results, only small short-lived Options.
Not as concise, but also much less surprising solution:
for (x <- l) {
x match {
case b: B[_] => println(b.v)
case _ => /* do nothing */
}
}
If you could change the type of l to List[B[_]], this would be the preferable solution.
I think the most ideomatic way to do it would be to supply B with an extractor object and pattern match for B values:
object B {
def unapply[T](arg: B[T]): Some[T] = Some(arg.v)
}
l.collect{case B(x) => println(x)}
If B is declared in a source file you can't alter you might need a different name for the extractor object.

Scala Type Inference Confusion: Any or Nothing?

Original Version:
trait Animal[F[_], A]
case class Cat[F[_], I, A](limits: F[I], f: I => A) extends Animal[F,A]
object ConfuseMe {
def confuse[F[_], A](tt: Animal[F, A]) = tt match {
case Cat(_, f) => f
}
}
Modified Version:
trait Animal[A]
case class Cat[I, A](f: I => A) extends Animal[A]
object ConfuseMe {
def confuse[A](tt: Animal[A]) = tt match {
case Cat(f) => f
}
}
If F is List, function confuse of original version will be inferred as Any => A type. The modified version will be inferred as Nothing => A type as default. Why not both of them are of type Nothing => A as implied by IntelliJ IDE? I'm totally confused.
Other Interesting Example:
trait Trampoline[+A]
case class Done[+A](get: A) extends Trampoline[A]
case class More[+A](force: () => Trampoline[A]) extends Trampoline[A]
case class Bind[I,+A](force: () => Trampoline[I], f: I => Trampoline[A]) extends Trampoline[A]
It seems like once we have constraints(type constructor) 'Trampoline' over type 'I' here, we have something to say about 'I' like type 'I' have property of 'F'(it could be any type-constructor?), so it will inferred as 'Any' by Scala complier(it doesn't further typecheck type-constructor 'F' to gather more information about 'I', so it just give it 'Any' because it is not SMART enough) otherwise it is tagged 'Nothing' just like we have nothing to say. However, I'm not sure about it and still stuck in confusion.

Scala: Implementing a generic fold

I don't understand why thid fold doesn't compile. Could anyone give me a clue?
sealed trait ListG[A] {
def fold[A,B](end: B, f: (A,B) => B): B = this match {
case End() => end
case Cons(hd,tl) => f(hd, tl.fold(end,f))
}
}
Error:(20, 28) type mismatch;
found : hd.type (with underlying type A)
required: A
case Cons(hd,tl) => f(hd, tl.fold(end,f))
^
final case class EndA extends ListG[A]
final case class Cons[A](hd:A, tl:ListG[A]) extends ListG[A]
You're shadowing type parameter A of ListG when you define an additional type parameter A on the fold function.
Adding type ascription appears to fix the problem.
case Cons(hd:A, tl) => ...
^^
There is a warning about type erasure but it does compile and appears to run.

Scala pattern match infers `Any` instead of an existential type, breaks type safety?

I ran into a puzzling type inference problem with case classes. Here's a minimal example:
trait T[X]
case class Thing[A, B, X](a: A, f: A => B) extends T[X]
def hmm[X](t: T[X]) = t match {
case Thing(a, f) => f("this really shouldn't typecheck")
}
Scala decides that a: Any and f: Any => Any, but that's inappropriate; they really ought to have types a: SomeTypeA and f: SomeTypeA => SomeTypeB, where SomeTypeA and SomeTypeB are unknown types.
Another way of saying this is that I think the hypothetical Thing.unapply method should look something like
def unapply[X](t: T[X]): Option[(A, A => B)] forSome { type A; type B } = {
t match {
case thing: Thing[_, _, X] => Some((thing.a, thing.f))
}
}
This version correctly gives a type error at f("this really shouldn't typecheck").
Does this seem like a bug in the compiler, or am I missing something?
Edit: This is on Scala 2.10.3.
Mark Harrah pointed this out in the #scala channel on Freenode: yes, this is a bug.
https://issues.scala-lang.org/browse/SI-6680

How would I implement a widen function on Function1 or PartialFunction

I would like to define a widen function on Function1 or PartialFunction.
I want to do this because I have a use case similar to the following:
class A
class B extends A
def foo(fun: Function[B, A]) = {
bar(fun.widen[A])
}
def bar(pf: PartialFunction[A, A]) = ???
As can be seen above, in order to accomplish this, I thought of defining a widen function such as this:
implicit class AugmentedFunction[T, U](fun: T => U) {
def widen[T1 >: T]: PartialFunction[T1, U] = { case t: T => fun(t) }
}
But unfortunately this does not work because of erasure. I tried looking into using TypeTags but I couldn't seem to express this in a way that satisfied the compiler.
Clarification:
When I say it does not work, I mean it throws an exception when used (see ScalaKata code snippet) when it should actually not throw an exception and print "not defined" in the particular case of the code snippet on ScalaKata.
My question:
How could I go about solving this problem correctly? Is there already such functionality in Scalaz or Shapeless that I am unaware of? Does it make any sense to be doing this in the first place?
Here is a snippet with all the code: http://www.scalakata.com/527bb729e4b0b1a1c4db1a73
I think you can do this with class manifests:
implicit class AugmentedFunction[T, U](fun: T => U)(implicit m: Manifest[T]) {
def widen[T1](implicit m1: Manifest[T1]): PartialFunction[T1, U] = {
case a if(m <:< m1) => fun(a.asInstanceOf[T])
}
}
class A
class B extends A
class C
val theFun: B => A = (b: B) => b
theFun.widen[A].isDefinedAt(new B) // true
theFun.widen[C].isDefinedAt(new C) // false
Well the error says it all : java.lang.ClassCastException: ScalaKata$A$1 cannot be cast to ScalaKata$B$1. Basically when you call foo( (a: B) => new A, new A) the A value is passed to the lambda which actually accepts type B as param and hence the exception while casting from A to B as that is not possible to cast from generic to specific.
You have to use something like:
foo( (a: Ai) => new Ai, new Ai)
foo( (a: Ci) => new Ai, new Ci)
foo( (a: Ai) => new Ai, new Bi)
Basically, the 2nd parameter should be a subtype of the lambda argument type.
Implementation by using TypeTag (because Manifest is deprecated)
import scala.reflect.runtime.universe._
implicit class AugmentedFunction[T : TypeTag, U](fun: T => U) {
def widen[T1 : TypeTag]: PartialFunction[T1, U] = {
case a if typeOf[T] <:< typeOf[T1] => fun(a.asInstanceOf[T])
}
}