Scala inferring wrong type when using Seq append operator "+:" - scala

I'm still pretty new to Scala. I'm having trouble trying to append two Sequences together because the compiler is complaining about the type of the Seq. I would like to start with a Seq[String] var and replace it with the addition of two Seq[String]'s. In the REPL session below, we see that y :+ x is a Seq[Object], but why?
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_71).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val x = Seq[String]("a")
x: Seq[String] = List(a)
scala> var y = Seq[String]("b")
y: Seq[String] = List(b)
scala> y = y :+ x
<console>:9: error: type mismatch;
found : Seq[Object]
required: Seq[String]
y = y :+ x
^
scala> val z = y :+ x
z: Seq[Object] = List(b, List(a))

It's because the :+ operator expects a single item, not a sequence. So what you're trying to do is comparable to var y:List[String] = List("b", List("a")), which isn't valid. You can see this in the documentation of Seq, which shows the type of :+ to be A => Seq[A].
I think you probably want to use the ++ operator instead.

Related

Right not working with for comprehension Scala

Background
I am trying to use comprehensions with Scala with the Either type, namely using a Right.
However, despite my efforts, I get an error and nothing works.
Code
I am using scala's repl to make a few tests. This is the easiest use case I could come up with:
scala> for {
| x <- Right(1)
| y <- Right(2)
| z <- Right(3)
| } yield x + y + z
You will see it is basically a copy of this page:
https://www.scala-lang.org/api/2.12.7/scala/util/Either.html
Problem
However, this fails with the following error:
<console>:13: error: value flatMap is not a member of scala.util.Right[Nothing,Int]
x <- Right(1)
^
<console>:14: error: value flatMap is not a member of scala.util.Right[Nothing,Int]
y <- Right(2)
^
<console>:15: error: value map is not a member of scala.util.Right[Nothing,Int]
z <- Right(3)
^
I am using using the following version of scala:
Welcome to Scala 2.11.12 (OpenJDK 64-Bit Server VM, Java 11.0.13).
Type in expressions for evaluation. Or try :help.
I understand some changes were made to Either, so it became Right biased, but I don't see how such changes could affect this example.
What am I missing?
In scala 2.11 Either is not a Monad. Combinators like flatMap and map are missing from it. Instead, you call .right or .left to get a RightProjection or LeftProjection which does have the combinators. You need to project your Either as right. The code below will return Right(6).
for {
x <- Right(1).right
y <- Right(2).right
z <- Right(3).right
} yield x + y + z

Scala: Option[T] as ?[T] (or even T?)

i tried
type ?[_] = Option[_]
def f(x: ?[Int]) = for (y <- x) yield y
(but i don't know what i am doing.)
insofar as types are just objects, i should be able to define a postix operator (i.e. zero arity method) for use in type signatures (i think). it might need a space like
def f(x: Int ?) = for (y <- x) yield y
scala makes it easy to use the Option type with matching and polymorphism, avoid null. but, most classes are (nullable) vars and java often returns vars. using classes and calling java are two of scala's selling points. an easy-to-write and easy-to-read syntax would support Options even more strongly.
what are all the things that scala does with "?" that make its parsing special.
ideally, one could write
def f(x: Int?) = for (y <- x) yield y
like other languages. can we do this in scala (without a macro)?
First, types are not objects. In fact, Scala has exactly two namespaces: values and types. They are very different things, and play by very different rules.
The postfix idea is kind of nice, actually, but it is not possible. There's an infix notation for types, though.
Now, to what you wrote:
type ?[_] = Option[_]
Each underscore has a different meaning. The underscore in ?[_] means ? is higher-kinded, but you don't care what it's type parameter is. The underscore in Option[_] means Option is an existential type. So when you write x: ?[Int], Scala will convert it to x: Option[t] { forSome type t }. This means that not only you don't get the Int, but the type parameter of Option is unknowable (you just know it exists).
However, it does compile:
scala> def f(x: ?[Int]) = for (y <- x) yield y
f: (x: ?[Int])Option[Any]
Which version of Scala did you use? 2.11? A co-worker of mine has already found some type inference regressions on 2.11, so that could be it.
The proper way to write the type alias would be this:
type ?[+A] = Option[A]
Not only we pass the type parameter along (it is a parameter, after all!), but we need to specify co-variance for it to act just Option (which is co-variant itself).
Now, as to your two questions, Scala has absolutely no special treatment of ?. And, no, you can't do this. This ? is not exactly widespread among languages either, and in all of them that support it, it is built in the language, and not something externally defined.
Besides, it's kind of a joke that, when interface with Java, typing out Option would be a problem -- not with the average identifier size in Java!
You intended to get an Option[Int] out:
scala> type ?[A] = Option[A]
defined type alias $qmark
scala> def f(x: ?[Int]) = for (y <- x) yield y + 1
f: (x: ?[Int])Option[Int]
and it does compile anyway.
You could maybe
scala> type ?[A,_] = Option[A]
defined type alias $qmark
scala> def f(x: Int ? _) = for (y <- x) yield y + 1
f: (x: ?[Int, _])Option[Int]
or similar.
scala> def f(x: Int ?_) = for (y <- x) yield y + 1
f: (x: ?[Int, _])Option[Int]
looks more postfixy.
P.S. Still curious whether variance annotation on type alias is required or merely advisable.
scala> type ?[A] = Option[A]
defined type alias $qmark
scala> trait X ; trait Y extends X ; trait Z extends X
defined trait X
defined trait Y
defined trait Z
scala> val x: ?[X] = null.asInstanceOf[?[Y]] // why is this OK?
x: ?[X] = null
scala> class C[A]
defined class C
scala> val c: C[X] = null.asInstanceOf[C[Y]] // like this is not OK
<console>:10: error: type mismatch;
found : C[Y]
required: C[X]
Note: Y <: X, but class C is invariant in type A.
You may wish to define A as +A instead. (SLS 4.5)
val c: C[X] = null.asInstanceOf[C[Y]]
^
Maybe compare SI-8522 and related issues.
You might consider a renaming import. When you create a type alias you only rename a type. When you rename a symbol during import you include all referents of that name, both type and value.
To wit:
scala> import scala.{Option => ?}
import scala.{Option=>$qmark}
scala> val oi1: ?[Int] = Some(1)
oi1: Option[Int] = Some(1)
scala> def mi1(oi: ?[Int]): Int = oi.getOrElse(-1)
mi1: (oi: Option[Int])Int
scala> mi1(None)
res1: Int = -1
scala> mi1(?(1))
res2: Int = 1
Compare with this:
scala> type ?[A] = Option[A]
scala> def mi1(oi: ?[Int]): Int = oi.getOrElse(-1)
mi1: (oi: ?[Int])Int
scala> mi1(?(1))
<console>:10: error: not found: value ?
mi1(?(1))
^

Scala applying implicit functions to a collection

EDIT: I'm using Scala 2.9.2
In Scala, I've defined a custom class which wraps a Double:
class DoubleWrap( d : Double ) {
def double( ) = d * 2
}
and an implicit conversion from Double to DoubleWrap:
implicit def wrapDouble( d : Double ) = new DoubleWrap( d )
This allows me to do the following:
scala> 2.5.double
res0: Double = 5.0
However, since there is an implicit conversion in Scala from Int to Double, I can also do the following:
scala> 2.double
res1: Double = 4.0
This operator can also be applied to all elements of a double-type collection using map
scala> List( 1.0, 2.0, 3.0 ).map( _.double )
res2: List[Double] = List(2.0, 4.0, 6.0)
However, if I attempt to apply the function to all elements of an integer collection, it doesn't work:
scala> List( 1, 2, 3 ).map( _.double )
<console>:10: error: value double is not a member of Int
List( 1, 2, 3 ).map( _.double )
Does anyone know why this is the case?
In scala, implicit conversions are not automatically chained. In other words, the compiler will look for a single implicit conversion that will allow the code to make sense, it will never try to apply two (or more) successive implicit conversions.
In your example, the fact that you can do 2.double has nothing to do with the fact that there is an implicit conversion from Double to Int in Predef.
As a proof, try this in the REPL:
scala> val i: Int = 2
i: Int = 2
scala> i.double
<console>:13: error: value double is not a member of Int
i.double
It does not compile.
So why does 2.double compile? Good question.
I thought I understood this intuitively: 2 can be interpreted as the Int value 2 or as the Double value 2.0 in the first place, so my intuition was that 2 is somehow already a Double in this context.
However, I think this is wrong, because even the following will compile, surpisingly: (2:Int).double (or even more strange: ((1+1):Int).double). I'll be honest, I am flabbergasted and have no idea why this compiles while val i: Int = 2; i.double does not.
So to sum up, it is normal that scala does not try to apply two implicit conversions at the same time, but for some reason this rule does not seem to apply to constant expressions.
And now for a way to fix your issue: simply modify your implicit conversion so that it accepts any type that is itself implicitly convertible to Double. In effect, this allows to chain the implicit conversions:
implicit def wrapDouble[T <% Double]( d : T ) = new DoubleWrap( d )
It's a bug which should soon be fixed.

Not sure where my assignment is going

I ran into some issues today making assignments to a var field in a case class instance stored in a map. Here's a simple session in the repl demonstrating the problem:
scala> case class X(var x: Int)
defined class X
scala> val m = Map('x -> X(1))
m: scala.collection.immutable.Map[Symbol,X] = Map('x -> X(1))
scala> m
res0: scala.collection.immutable.Map[Symbol,X] = Map('x -> X(1))
scala> m('x).x = 7
scala> m
res1: scala.collection.immutable.Map[Symbol,X] = Map('x -> X(1))
scala> val x = m('x)
x: X = X(1)
scala> x.x = 7
x.x: Int = 7
scala> x
res2: X = X(7)
scala> m
res3: scala.collection.immutable.Map[Symbol,X] = Map('x -> X(7))
scala> m('x).x_=(8)
scala> m
res5: scala.collection.immutable.Map[Symbol,X] = Map('x -> X(8))
The first attempt at assignment does nothing. However, storing the instance in a val and then doing the assignment works, as does directly calling the assignment method for the field.
I'm using Scala 2.9.2.
If this is expected behavior, it would be nice if someone could explain it to me because I can't seem to make sense of it right now. If this is a bug then that would be good to know as well.
Either way, it would also be interesting to know where that first m('x).x = 7 assignment is going. I assume something is getting mutated somewhere—I just have no idea what that something could be.
Update: It looks like this only happens in the repl. I just tried compiling the code and the assignment happens as expected. So, what is the repl doing to my assignment?
This seems to be a bug. If one executes this with a 2.10 nightly an error message is thrown:
scala> m('x).x = 7
<console>:10: error: ')' expected but string literal found.
+ "m(scala.Symbol("x")).x: Int = " + `$ires0` + "\n"
^
I created a ticket for this.

Polymorphic dot product in Scala and anonymous function shorthand

I'd like to implement a "matrix dot product" in Scala in the following way:
type Real = Double
type Row = Array[Real]
type Matrix = Array[Row]
def dot[T](f: (T,T) => Real)(as: Iterable[T], bs: Iterable[T]): Real =
(for ((a, b) <- as zip bs) yield f(a, b)) sum
def rowDot(r1: Row, r2: Row) = dot(_*_)(r1, r2)
def matDot(m1: Matrix, m2: Matrix) = dot(rowDot)(m1, m2)
However, the definition of rowDot doesn't work. Scala needs explicit type annotations for the anonymous function (_*_), so instead I must write
def rowDot(r1: Row, r2: Row) = dot((x:Real, y: Real) => x*y)(r1, r2)
or
def rowDot = dot((x:Real, y: Real) => x*y) _
Is there some way to change the definition of dot so that the shorthand (_*_) can be used?
Edit: Another confusion: matDot also gives type errors in certain circumstances. It fails with Arrays of Arrays, but not with Lists of Arrays
scala> matDot(Array(Array(1.0,2.0)), Array(Array(1.0,2.0,3.0)))
<console>:27: error: type mismatch;
found : Array[Array[Double]]
required: Iterable[Iterable[Real]]
matDot(Array(Array(1.0,2.0)), Array(Array(1.0,2.0,3.0)))
^
scala> matDot(List(Array(1.0,2.0)), List(Array(1.0,2.0,3.0)))
res135: Real = 5.0
What's the difference?
specifying dot[Real] explicitly should work too.
def rowDot(r1: Row, r2: Row) = dot[Real](_*_)(r1, r2)
EDIT
replying to your edit: I think the issue is that the implicit conversion from Array to WrappedArray is not applied recursively when you have a Array[Array].
Array[Int] is not an Iterable[Int]; normally, when you assign it to a Iterable, an Array[Int] is implicitly converted to a WrappedArray[Int] (where WrappedArray is a Iterable[Int]). This is what happens when you use List[Array[Int]] (you get a List[WrappedArray[Int]] implicitly).
However, as I said, the implicit conversion is not applied recursively, so an Array[Array[Int]] is not implicitly converted to WrappedArray[WrappedArray[Int]].
Here's a REPL session that demonstrates the problem:
A List[Array[Int]] can be assigned to Iterable[Iterable[Int]] (note that Array is converted to WrappedArray)
scala> val i : Iterable[Iterable[Int]] = List(Array(1,2), Array(1,2,3))
i: Iterable[Iterable[Int]] = List(WrappedArray(1, 2), WrappedArray(1, 2, 3))
An Array[Array[Int]] does not work automatically (as you discovered)
scala> val j : Iterable[Iterable[Int]] = Array(Array(1,2), Array(1,2,3))
<console>:9: error: type mismatch;
found : Array[Array[Int]]
required: Iterable[Iterable[Int]]
val j : Iterable[Iterable[Int]] = Array(Array(1,2), Array(1,2,3))
^
However, with some hand-holding (converting manually the inner Arrays to WrappedArrays) everything works again:
scala> import scala.collection.mutable.WrappedArray
import scala.collection.mutable.WrappedArray
scala> val k : Iterable[Iterable[Int]] = Array(WrappedArray.make(Array(1,2)),
WrappedArray.make(Array(1,2,3)))
k: Iterable[Iterable[Int]] = WrappedArray(WrappedArray(1, 2), WrappedArray(1, 2,
3))
Yes - if you switch your argument lists around. Type inference on function parameters works more effectively when the function parameter is alone in the last argument list:
def dot[T](as: Iterable[T], bs: Iterable[T])(f: (T,T) => Real): Real =
(for ((a, b) <- as zip bs) yield f(a, b)) sum
def rowDot(r1: Row, r2: Row) = dot(r1, r2)(_*_)