how do you define a Scala method such that it would take in the subclass of any type A without throwing a compilation error?
trait A
case class B extends A
case class C extends A
case class W[T](abc: Option[T]= None)
def methodOne(a: A): W[A] = {
a match {
case b:B => methodTwo() // throws compilation error
case c:C => methodThree() // throws compilation error
}
}
def methodTwo(): W[B] = y
def methodThree(): W[C] = z
Have tried something like
def methodOne[T <: A](a: A): W[T]
but it doesn't allow to compile still
If you want forall T <: A to imply W[T] <: W[A], you need to make W covariant:
case class W[+T](abc: Option[T] = None)
object X {
def methodOne(a: A): W[A] = {
a match {
case b: B => methodTwo()
case c: C => methodThree()
}
}
def methodTwo(): W[B] = ???
def methodThree(): W[C] = ???
}
For basic coverage of variance, see this post.
You need to make W covariant. You can do this easily by defining it as W[+T]:
case class W[+T](abc: Option[T] = None)
This way if B is a subtype of A, W[B] is also a subtype of W[A].
Option for example is defined as Option[+T], therefore Option[B] is a subtype of Option[A].
You can checkout the official scala docs for more details
Related
I'm trying to perform a Natural Transformation between kinds of * -> * -> *
so I want to take F[A, B] => G[A, B]
Specifically I'm trying to define a DSL that I can then convert into actual function definitions, so MyDSL[A, B] => Function[A, B]
Here is the Natural Transformation definition:
trait ~~>[F[_, _], G[_, _]] {
def apply[A, B](fab: F[A, B]): G[A, B]
}
object ~~> {
def apply[F[_, _], G[_, _]](implicit f2g: F ~~> G): F ~~> G = f2g
}
The DSL looks like so:
sealed trait MyDSL[A, B]
object MyDSL {
case object Add1 extends MyDSL[Int, Int]
case object Show extends MyDSL[Int, String]
implicit def dsltoF: MyDSL ~~> Function = new ~~>[MyDSL, Function] {
override def apply[A, B](fab: MyDSL[A, B]): Function[A, B] = fab match {
case Add1 => i => i + 1
case Show => i => i.toString
}
}
}
Using the Natural Transformation directly works fine:
dsltoF(Add1)
output: res0: Function[Int,Int] = MyDSL$$anon$2$$Lambda$1816/700824958#6f3aa425
It even works in the case where the function returned is a method taking 2 type parameters.
When I try to define a DSL object that converts using a generic method of one type parameter it has issues.
case class Id[A]() extends MyDSL[A, A]
implicit def dsltoF: MyDSL ~~> Function = new ~~>[MyDSL, Function] {
override def apply[A, B](fab: MyDSL[A, B]): Function[A, B] = fab match {
case Id() => identity[A] _
case Add1 => i => i + 1
case Show => i => i.toString
}
}
I get a found A required B compilation error.
Scala doesn't recognize that B is A in this case.
I get why, as the type parameters A & B aren't necessarily correlated properly to the definition of the function I am returning, therefore even writing:
case Add1 => i => i + 1
there is red lines in IntelliJ as it doesn't realize that even though Add "is a" MyDSL[Int, Int]. Though Scala is ok with this.
The type parameters are open to all possibilities on the method signature of apply on the Natural Transformation, but in this case it needs some sort of restriction. My guess is since there is no value within the DSL case class to restrict the type parameter, it comes down to the pattern match, which is already past where Scala interprets the signature of the method, and therefore it expects a different type B and it barks.
I can of course get around this via .asInstanceOf nastiness, but I mean come on.
Any thoughts of a different strategy to get this to work would be appreciated.
That's a known restriction in the type inference system in the current versions of the language, which should be lifted in future versions.
In this case, you can use type variables in the pattern match to work around this restriction:
import scala.language.higherKinds
trait ~~>[F[_, _], G[_, _]] {
def apply[A, B](fab: F[A, B]): G[A, B]
}
object ~~> {
def apply[F[_, _], G[_, _]](implicit f2g: F ~~> G): F ~~> G = f2g
}
sealed trait MyDSL[A, B]
object MyDSL {
case class Id[A]() extends MyDSL[A, A]
case class Const[A, B](constantResult: B) extends MyDSL[A, B]
case object Add1 extends MyDSL[Int, Int]
case object Show extends MyDSL[Int, String]
implicit def dsltoF: MyDSL ~~> Function = new (MyDSL ~~> Function) {
override def apply[A, B](fab: MyDSL[A, B]): Function[A, B] = fab match {
case _: Id[x] => identity[x] _
case c: Const[a, b] => (_ => c.constantResult)
case Add1 => i => i + 1
case Show => i => i.toString
}
}
}
Essentially: if there is no "place" where the compiler could deposit more specific type information, just give it a type-variable in the pattern so it can attach the inferred type information to it.
I'm writing an FRM, with the fields abstracted over F[_].
trait Query[A]
case class Field[A](name: String)
case class DBTable[T[_[_]]](fields: T[Field]) extends Query[T[Field]]
// example table
case class PersonalInfo[F[_]](name: F[String], age: F[Int])
I want to perform query rewrites using recursion schemes, so I need to define a pattern functor,
trait QueryF[A, B]
case class DBTableF[T[_[_]], B](fields: T[Field]) extends QueryF[T[Field], B]
and then a coalgebra to lift the Query into it:
type Coalgebra[F[_], A] = A => F[A]
def coalg[A]: Coalgebra[QueryF[A, ?], Query[A]] = {
case DBTable(fields) => DBTableF(fields)
}
This works, but defining an algebra to convert in the opposite direction does not:
type Algebra[F[_], A] = F[A] => A
def alg[A]: Algebra[QueryF[A, ?], Query[A]] = {
case DBTableF(value) => DBTable[A](value)
}
the alg function throws a compiler error, saying constructor of type controllers.thing.DBTableF[T,B] cannot be uniquely instantiated to expected type controllers.thing.QueryF[?,controllers.thing.Query[?]
How about this here:
import scala.language.higherKinds
trait Query[A]
case class Field[A](name: String)
case class DBTable[T[_[_]]](fields: T[Field]) extends Query[T[Field]]
trait QueryF[A, B]
case class DBTableF[T[_[_]], B](fields: T[Field]) extends QueryF[T[Field], B]
type Coalgebra[F[_], A] = A => F[A]
def coalg[A]: Coalgebra[({ type L[X] = QueryF[A, X]})#L, Query[A]] = {
case DBTable(fields) => DBTableF(fields)
}
type Algebra[F[_], A] = F[A] => A
def alg[A]: Algebra[({ type L[X] = QueryF[A, X]})#L, Query[A]] = {
case dbtf: DBTableF[t, b] => DBTable(dbtf.fields)
}
or alternatively, with the last case replaced by:
case dbtf: DBTableF[t, b] => DBTable[t](dbtf.fields)
if this is a bit clearer.
Both variants compile with -Ypartial-unification on 2.12.6.
I have a problem with having a Function1 in my trait and make things work correctly, let's say I have the following trait
trait Foo[+X, +O, Z<:X]{
def bar: Z => O
def args:Option[Z]
}
case class A1(args:Option[String] = None) extends Foo[String,String,String]{
def bar = (x:String) => x+"..."
}
case class A2(args:Option[Int] = None) extends Foo[Int,String,Int]{
def bar = (x:Int) => x.toString
}
val mylist = List(A1(),A2())
The reason that I have type Z is for type signature of Function1 which is [T1-,R+]. I want mylist has type of Foo[Any,Any,Any] now it is Foo[Any,Any,_ >: Int with String]. So basically I want Z to be covariant too which is impossible. How should I define my trait to solve these problems?
According to the scala specification, the extractor built by case classes is the following (scala specification §5.3.2):
def unapply[tps](x: c[tps]) =
if (x eq null) scala.None
else scala.Some(x.xs11, ..., x.xs1k)
For implementation reasons, I want to be able to mimic the behavior of this extractor on a non-case class.
However, my implementation fails to reproduce the same behavior.
Here is an example of the difference i have:
trait A
sealed trait B[X <: A]{ val x: X }
case class C[X <: A](x: X) extends B[X]
class D[X <: A](val x: X) extends B[X]
object D {
def unapply[X <: A](d: D[X]): Option[X] =
if (d eq None) None
else Some(d.x)
}
def ext[X <: A](b: B[X]) = b match {
case C(x) => Some(x)
case D(x) => Some(x)
case _ => None
}
I have the following warning :
<console>:37: warning: non variable type-argument X in type pattern D[X] is unchecked since it is eliminated by erasure
case D(x) => Some(x)
Notice the warning occurs only in the D case, not in the case-class textractor case.
Do you have any idea about the cause of the warning / about what I should do to avoid this warning ?
Note: If you want to test it in REPL, the easiest way is:
To activate unchecked warning
scala> :power
scala> settings.unchecked.value = true
To copy above code in paste mode:
scala> :paste
[copy/paste]
[ctrl + D]
Edit: As Antoras mentioned it should be a compiler bug, maybe the scala version could be useful: scala 2.9.0.1
(after a quick test, still there in scala 2.9.1RC2)
This seems to be a compiler bug. I have analyzed the output of the compiler AST (with fsc -Xprint:typer <name_of_file>.scala). It interprets both as the same:
...
final <synthetic> object C extends java.lang.Object with ScalaObject with Serializable {
def this(): object test.Test.C = {
C.super.this();
()
};
final override def toString(): java.lang.String = "C";
case <synthetic> def unapply[X >: Nothing <: test.Test.A](x$0: test.Test.C[X]): Option[X] = if (x$0.==(null))
scala.this.None
else
scala.Some.apply[X](x$0.x);
case <synthetic> def apply[X >: Nothing <: test.Test.A](x: X): test.Test.C[X] = new test.Test.C[X](x);
protected def readResolve(): java.lang.Object = Test.this.C
};
...
final object D extends java.lang.Object with ScalaObject {
def this(): object test.Test.D = {
D.super.this();
()
};
def unapply[X >: Nothing <: test.Test.A](d: test.Test.D[X]): Option[X] = if (d.eq(null))
scala.None
else
scala.Some.apply[X](d.x)
};
...
The method signature of both methods unapply are identical.
Furthermore the code works fine (as expected due to identical methods):
trait A {
def m = "hello"
}
class AA extends A
sealed trait B[X <: A]{ val x: X }
case class C[X <: A](x: X) extends B[X]
class D[X <: A](val x: X) extends B[X]
object D {
def apply[X <: A](x: X) = new D(x)
def unapply[X <: A](d: D[X]): Option[X] =
if (d eq null) None
else Some(d.x)
}
def ext[X <: A](b: B[X]) = b match {
case C(x) => Some("c:"+x.m)
case D(x) => Some("d:"+x.m)
case _ => None
}
println(ext(C[AA](new AA())))
println(ext(D[AA](new AA())))
I've been playing around with Scalaz to get a little bit of the haskell feeling into scala. To
understand how things work in scala I started implementing various algebraic structures myself and came across a behavior that has been mentioned by the Scalaz folks.
Here is my example code which implements a functor:
trait Functor[M[_]] {
def fmap[A, B](a: M[A], b: A => B): M[B]
}
sealed abstract class Foo[+A]
case class Bar[A]() extends Foo[A]
case class Baz[A]() extends Foo[A]
object Functor {
implicit val optionFunctor: Functor[Option] = new Functor[Option]{
def fmap[A, B](a: Option[A], b: A => B): Option[B] = a match {
case Some(x) => Some(b(x))
case None => None
}
}
implicit val fooFunctor: Functor[Foo] = new Functor[Foo] {
def fmap[A, B](a: Foo[A], b: A => B): Foo[B] = a match {
case Bar() => Bar()
case Baz() => Baz()
}
}
}
object Main {
import Functor._
def some[A](a: A): Option[A] = Some(a)
def none[A]: Option[A] = None
def fmap[M[_], A, B](a: M[A])(b: A => B)(implicit f: Functor[M]): M[B] =
f.fmap(a, b)
def main(args: Array[String]): Unit = {
println(fmap (some(1))(_ + 1))
println(fmap (none)((_: Int) + 1))
println(fmap (Bar(): Foo[Int])((_: Int) + 1))
}
}
I wrote a functor instance for Option and a bogus sumtype Foo. The problem is that scala cannot infer the implicit parameter without an explicit type annotation or a wrapper method
def some[A](a: A): Option[A] = Some(a)
println(fmap (Bar(): Foo[Int])((_: Int) + 1))
Scala infers types like Functor[Bar] and Functor[Some] without those workarounds.
Why is that? Could anyone please point me to the section in the language spec that defines this behavior?
Regards,
raichoo
You're asking the compiler to perform two tasks: local type inference (§6.26.4) of the type arguments to fmap, and an implicit search for implicit parameter (§7.2) f. References are to the Scala Reference.
Things go in roughly this order:
fmap[M = ?, A = ?, B = ?](Some(1))(x => x)
// type the arguments of the first parameter section. This is done
// without an expected type, as `M` and `A` are undetermined.
fmap[M = ?, A = ?, B = ?](Some(1): Some[Int])(x => x)(?)
// local type inference determines `M` and `A`
fmap[Some, Int, B = ?](Some(1): Some[Int])(x => x)(?)
// move to the second parameter section, type the argument with the expected type
// `Function1[Int, ?]`. The argument has the type `Function1[Int, Int]`
fmap[Some, Int, ?](Some(1): Some[Int])((x: Int) => x)
// local type inference determines that B = Int
fmap[Some, Int, Int](Some(1): Some[Int])((x: Int) => x)
// search local identifiers, and failing that the implicit scope of type `Functor[Some]]`, for an implicit
// value that conforms to `Functor[Some]`
fmap[Some, Int, Int](Some(1): Some[Int])((x: Int) => x)(implicitly[Functor[Some]])
The implicit search for Functor[Some] fails; Functor[Option] doesn't conform.