What's wrong with this piece of scala code? - scala

I have the following code snippet which can not be compiled:
val cids = List(1, 2, 3, 4)
val b = Map.newBuilder[Int, Int]
for (c <- cids) {
b += (c, c*2)
}
b.result()
Compiler reports that
console>:11: error: type mismatch;
found : Int
required: (Int, Int)
b += (c, c*2)
I have no idea what's the mistake.

This would work:
for (c <- cids) {
b += ((c, c*2))
}
The parenthesis are parsed by compiler as the argument-list parenthesis of the += function, and not as a tuple. Adding nested parenthesis means a tuple is passed as the argument. It is confusing...

You can fix it the following way:
b += (c->c*2)

This is a duplicate question.
Normally, supplying an untupled arg list works as shown, but it doesn't work when the method is overloaded, because it will choose the method you didn't intend, and not bother to try auto-tupling your args.
scala> class C[A] { def f(a: A) = 42 }
defined class C
scala> val c = new C[(String, Int)]
c: C[(String, Int)] = C#3a022576
scala> c.f("1", 1)
res0: Int = 42
scala> class C[A] { def f(a: A) = 42 ; def f(a: A, b: A, rest: A*) = 17 }
defined class C
scala> val c = new C[(String, Int)]
c: C[(String, Int)] = C#f9cab00
scala> c.f("1", 1)
<console>:14: error: type mismatch;
found : String("1")
required: (String, Int)
c.f("1", 1)
^

An approach using (immutable) values,
(cids zip cids.map(_ * 2)).toMap
Using zip we pair each value with its double, and the resulting list is converted to a Map.

If you go to the documentation you will find : this
The supported API is ms += (k -> v) . That is you need to use
for (c <- cids) {
b += (c -> c*2)
}
Alternately you could use the ((c, c*2)) syntax as suggested above. This is happening because the compiler has no way of knowing that the parentheses are for the tuple. It simply understands that argument as two parameters being passed to the += method.

Related

Short form of lambda doesn't work in inner function

Reading Advanced Scala With Cats I can see this line on page 60:
fa.map(g(f(_))) == fa.map(f).map(g)
I'm trying to do something like:
val l = List(1, 2, 3)
def g(v: Int) = v + 1
def f(v: Int) = v * 2
l.map(g(f(_)))
And I'm getting this error:
Error:(25, 12) type mismatch;
found : Int => Int
required: Int
l.map(g(f(_)))
This is okay:
l.map(x => g(f(x)))
l.map(g(_))
Can't understand why my example doesn't work, but in the book it is correct.
val l = List(1, 2, 3)
def g(v: Int) = v + 1
def f(v: Int) = v * 2
l.map(g(f(_)))
I will try to split your l.map(g(f(_))) into equivalent steps
val fun1 = f(_) // this returns a partially applied function Int => Int.
then
g(fun1) // will give you error because function g requires int as an argument whereas we are passing func1: Int => Int as input. This is the exact issue comes when you do g(f(_)).
The alternatives that you have mentioned is correct. My idea here is to demonstrate the ability of Scala’s function composition. I would like to do the same thing other available approaches.
val fun = f _ andThen g _
l.map(fun)
Same can be done with compose as well.
val fun1 = g _ compose f _
l.map(fun1)
Remember that composition is available only on Unary functions.
I would do this in following way:
scala> val g:Int => Int = _ + 1
g: Int => Int = <function1>
scala> val f:Int => Int = _ * 2
f: Int => Int = <function1>
scala> val l = List(1, 2, 3)
l: List[Int] = List(1, 2, 3)
scala> l map (g compose f)
res0: List[Int] = List(3, 5, 7)
When declaring a def you get a method which expects an argument provided when using its name in the code.
When declaring a function as a val you get a pure Function1 instance and you can operate on them with functional combinators normally.

Pattern Match on Tuple Values within 'for-comprension'?

Given:
scala> val x: Either[Boolean, (Int, Int)] = Right( (5, 10) )
x: Either[Boolean,(Int, Int)] = Right((5,10))
I'd like to pattern match on the first and second tuple values in x.right, but this didn't work:
scala> for {
| (a, b) <- x.right
| } yield a
<console>:14: error: constructor cannot be instantiated to expected type;
found : (T1, T2)
required: scala.util.Either[Nothing,(Int, Int)]
(a, b) <- x.right
^
I can do something like:
scala> for { a <- x.right } yield a match { case (x, y) => x }
res5: scala.util.Either[Boolean,Int] = Right(5)
But, is there any way for me to change my first, non-compiling code to work?
This is a known bug. See SI-7222.
For now, if you're going to rely on RightProjection, you'll have to match the entire tuple, and use the _1 and _2 accessors.
You could also use a right-biased Either such as scalaz.\/, though that would require Monoid[Boolean] in this example.

Scala's either with tuple as Right

Suppose I have following code:
val either: Either[String, (Int, Int)] = Right((1,2))
for {
(a, b) <- either.right
} yield a + b
When I evaluate it in REPL I get
:13: error: constructor cannot be instantiated to expected
type; found : (T1, T2) required:
scala.util.Either[Nothing,(Double, Double)]
(a, b) <- a.right
^ :14: error: not found: value a
} yield a + b
^
Why do I have such error? Can't I pattern match on tuple from Either's Right?
Issue seems to be a scala bug https://issues.scala-lang.org/browse/SI-7222. Converting the for comprehension to flatMap/map notation seems to work.
val either: Either[String, (Int, Int)] = Right((1, 2))
either.right.map {
case (a, b) =>
a + b
}
either: Either[String,(Int, Int)] = Right((1,2))
res0: Serializable with Product with scala.util.Either[String,Int] = Right(3)

Passing a individual arguments AND a Seq to a var-arg function

I know it's possible to pass individual arguments to a vararg function and it's possible to pass a seq using :_* but is it possible to pass both?
for example:
scala> object X { def y(s: String*) = println(s) }
defined module X
scala> X.y("a", "b", "c")
WrappedArray(a, b, c)
scala> X.y(Seq("a", "b", "c"):_*)
List(a, b, c)
scala> X.y("a", Seq("b", "c"):_*)
<console>:9: error: no `: _*' annotation allowed here
(such annotations are only allowed in arguments to *-parameters)
X.y("a", Seq("b", "c"):_*)
^
Edit: In Scala 2.10 (in case that matters)
Hacky but this should work well:
X.y(Seq("a") ++ Seq("b", "c"):_*)
If you look around in the Scala standard library you'll find this sort of pattern in places:
def doIt(arg: Thing)
def doIt(arg1: Thing, arg2: Thing, moreArgs: Thing*)
You can see this, e.g., in Set.+(...). It allows you to have any number of arguments without ambiguity in the overloads.
Addendum
Proof of concept:
scala> class DI { def doIt(i: Int) = 1; def doIt(i1: Int, i2: Int, iMore: Int*) = 2 + iMore.length }
defined class DI
scala> val di1 = new DI
di1: DI = DI#16ac0be1
scala> di1.doIt(0)
res1: Int = 1
scala> di1.doIt(1, 2)
res2: Int = 2
scala> di1.doIt(1, 2, 3)
res3: Int = 3
scala> di1.doIt(1, 2, List(3, 4, 5): _*)
res4: Int = 5

"update" method with variable-length index in Scala

I was writing code for something like an array with variable dimensions. What I do is to maintain a linear underlying collections and wrap it up with index access methods. Since the dimension of the data structure is not known, I write something like
def apply(i: Int*): Double = ...
And it works perfectly. However, I cannot do the same thing to update method and operators like +=, so I end up writing methods like
def set(v: Double, i: Int*) ...
def add(v: Double, i: Int*) ...
which is fine but not what I really want. I guess the problem about update may be fixed in two ways:
Change the order of arguments in update function, which makes it look weird.
Allow variable-length arguments not as the last one. I find this questions asked in a general setting and it can be solved by using currying functions, which does not apply here.
The problem about += seems more complicated and it even exists when the index is of fixed length. Maybe we can add an object that has += operator and use this(...) to get the object (so that this(...) += v will invoke some method as we expect), but that will conflict with the apply method.
If anyone has solution to any of the above questions or has a reason why we shouldn't be able to write code like this, please share your ideas! Thanks~
update is a fairly peculiar artefact in Scala because it is mainly syntactic sugar and doesn't correspond to any particular method signature. This means that we can be creative and give update an arity-polymorphic signature,
scala> class Indexed { def update[P <: Product](p: P) = p }
defined class Indexed
scala> val i = new Indexed
i: Indexed = Indexed#1ea0e836
scala> i(0) = 1.0
res0: (Int, Double) = (0,1.0)
scala> i(0, 1) = 1.0
res1: (Int, Int, Double) = (0,1,1.0)
scala> i(0, 1, 2) = 1.0
res2: (Int, Int, Int, Double) = (0,1,2,1.0)
scala> i(0, 1, 2, 3) = 1.0
res3: (Int, Int, Int, Int, Double) = (0,1,2,3,1.0)
As it stands, this leaves the types of the indices on the LHS and the type of the value on the RHS completely unconstrained,
scala> i(23, true, 'c') = "foo"
res4: (Int, Boolean, Char, String) = (23,true,c,foo)
but we can fix that with some implicit evidence provided by the new support for tuples in shapeless 2.0.0-SNAPSHOT,
scala> import shapeless._
import shapeless._
scala> import syntax.tuple._
import syntax.tuple._
scala> class Indexed {
| def update[P <: Product, I](p: P)
| (implicit
| init: TupleInit.Aux[P, I],
| toList: TupleToList[I, Int],
| last: TupleLast.Aux[P, Double]) = (toList(init(p)), last(p))
| }
defined class Indexed
scala> val i = new Indexed
i: Indexed = Indexed#76ab909a
scala> i(0) = 1.0
res10: (List[Int], Double) = (List(0),1.0)
scala> i(0, 1) = 2.0
res11: (List[Int], Double) = (List(0, 1),2.0)
scala> i(0, 1, 2) = 3.0
res12: (List[Int], Double) = (List(0, 1, 2),3.0)
scala> i(0, 1, 2, 3) = 4.0
res13: (List[Int], Double) = (List(0, 1, 2, 3),4.0)
scala> i(0, 1, 2) = "foo" // Doesn't compile
<console>:22: error: could not find implicit value for parameter
last: shapeless.ops.tuple.TupleLast.Aux[(Int, Int, Int, String),Double]
i(0, 1, 2) = "foo" // Doesn't compile
^
scala> i(23, "foo", true) = 5.0 // Doesn't compile
<console>:22: error: could not find implicit value for parameter
toList: shapeless.ops.tuple.TupleToList[I,Int]
i(23, "foo", true) = 5.0 // Doesn't compile
^
The simplest solution I see right now is to have many different overloads of update for every dimension that you want to support. Say that you can determine that the maximum dimension that you'll ever use is 10, this means that you'll need 10 overloads. This might not seem very practical, but i can easily be abstracted away so it is very much practical actually:
trait MultiKeyUpdate[K, V] {
def doUpdate( k: K* )( v: V )
def update(k1: K, v: V) { doUpdate( k1 )( v ) }
def update(k1: K, k2: K, v: V) { doUpdate( k1, k2 )( v ) }
def update(k1: K, k2: K, k3: K, v: V) { doUpdate( k1, k2, k3 )( v ) }
// ... and so on, up until max dimension ...
}
Usage:
class C extends MultiKeyUpdate[Int, Double] {
def apply(i: Int*): Double = {
println("Returning element " + i.mkString("[",",","]"))
123
}
def doUpdate( i: Int* )( v: Double ) {
println("Updating element " + i.mkString("[",",","]") + " to value " + v)
}
}
And some test in the REPL:
scala> val o = new C
o: C = C#12798c1
scala> o(1,2,3)
Returning element [1,2,3]
res3: Double = 123.0
scala> o(1,2,3) = 5.0
Updating element [1,2,3] to value 5.0
scala> o(1,2,3) += 7.0
Returning element [1,2,3]
Updating element [1,2,3] to value 130.0
class SetMe {
def set(i: Int*)(v: Double) { println("Set "+v+" with "+i.mkString(",")) }
}
scala> (new SetMe).set(4,7,19,3)(math.Pi)
Set 3.141592653589793 with 4,7,19,3
Can't do that trick with update itself, however. Might be worth filing an enhancement request.