Type mismatch in Scala's for-comprehension
Type mismatch in Scala's for-comprehension
I have tried to define a recursive Scala function that looks something like this:
def doSomething: (List[List[(Int, Int)]], List[(Int, Int)], Int, Int) => List[Int] =
(als, rs, d, n) =>
if (n == 0) {
for (entry <- rs if (entry._1 == d)) yield entry._2
} else {
for (entry <- rs; adj <- als(entry._1)) yield doSomething(als, rs.::((adj._1, adj._2 + entry._2)), d, n - 1)
}
Now, the compiler tells me:
| | | | | | <console>:17: error: type mismatch;
found : List[List[Int]]
required: List[Int]
for (entry <- rs; adj <- als(entry._1)) yield doSomething(als, rs.::((adj._1, adj._2 + entry._2)), d, n - 1)
^
| | | | | | <console>:17: error: type mismatch;
found : List[List[Int]]
required: List[Int]
for (entry <- rs; adj <- als(entry._1)) yield doSomething(als, rs.::((adj._1, adj._2 + entry._2)), d, n - 1)
^
I cannot figure out what the problem is. I'm sure that I'm using <-
correctly. On the other hand, I'm a Scala newbie coming from the Java world...
<-
Regarding the types of the input:
als
: List[List[(Int,Int)]]
,
als
List[List[(Int,Int)]]
rs
: List[(Int,Int)]
,
rs
List[(Int,Int)]
d
and n
: Int
d
n
Int
The compiler error appears as soon as I tell IntelliJ to send my code to the Scala console.
(List[List[(Int, Int)]], List[(Int, Int)], Int, Int)
Is it? What is
List[Int]
then? I always thought that the things on the left-hand side of the =>
are the input parameters...– Dmitrii C.
Jul 3 at 7:14
List[Int]
=>
@DmitriiC. is right.
als
is a List[List[(Int, Int)]]
, rs
is a List[(Int, Int)]
, d
and n
are Int
s.– marstran
Jul 3 at 7:19
als
List[List[(Int, Int)]]
rs
List[(Int, Int)]
d
n
Int
Some following the
[scala]
tag here on StackOverflow have noticed several of these questions, with recurring patterns in how the code is laid out (e.g.: declaring a function - and not a method - with a def
and using List
s a lot). Out of curiosity, do you mind if I ask whether there is a common source?– stefanobaghino
Jul 3 at 7:54
[scala]
def
List
Totally fine, it's just that apparently many of your fellow students have used StackOverflow in the last few days and noticing the pattern caused the curiosity. ;)
– stefanobaghino
Jul 3 at 14:03
2 Answers
2
When you yield
an A
when iterating on a List
, you return a List[A]
. doSomething
returns a List[Int]
, so by yielding that you return a List[List[Int]]
. You can unroll that like this:
yield
A
List
List[A]
doSomething
List[Int]
List[List[Int]]
def doSomethingElse(als: List[List[(Int, Int)]], rs: List[(Int, Int)], d: Int, n: Int): List[Int] =
if (n == 0) {
for ((k, v) <- rs if k == d) yield v
} else {
for {
(k, v) <- rs
(adjk, adjv) <- als(k)
item <- doSomethingElse(als, (adjk, adjv + v) :: rs, d, n - 1)
} yield item
}
Notice that I also used a method notation for brevity and destructured the pairs and leveraged the right-associativity of methods whose name ends in :
for readability, feel free to use whatever convention you might want (but I don't see really a reading why having a method that returns a constant function (maybe you'd want to just use a val
to declare it).
:
val
As a further note, you are using random access on a linear sequence (als(k)
), you may want to consider an indexed sequence (like a Vector
). More info on the complexity characteristics of the Scala Collection API can be found here.
als(k)
Vector
Thank you, that did the trick! :-)
– Dmitrii C.
Jul 3 at 7:57
for test purpose I created some sample data that meets the input datatypes as
val als = List(List((1,2), (3,4)), List((1,2), (3,4)), List((1,2), (3,4)))
//als: List[List[(Int, Int)]] = List(List((1,2), (3,4)), List((1,2), (3,4)), List((1,2), (3,4)))
val rs = List((1,2), (2,3))
//rs: List[(Int, Int)] = List((1,2), (2,3))
val d = 1
//d: Int = 1
val n = 3
//n: Int = 3
And in you doSomething function when n == 0
you are doing
n == 0
for (entry <- rs if (entry._1 == d)) yield entry._2
//res0: List[Int] = List(2)
You can see that the return type is List[Int]
List[Int]
And for the else part you are calling recursively doSomething.
I have created dummy doSomething
method of yours as your doSomething function definition lacks input variables as
doSomething
def dosomething(nn: Int)={
for (entry <- rs if (entry._1 == d)) yield entry._2
}
and I call the method recursively as
for (entry <- rs; adj <- als(entry._1)) yield dosomething(0)
//res1: List[List[Int]] = List(List(2), List(2), List(2), List(2))
Clearly you can see that the second nested for loop is returning List[List[Int]]
List[List[Int]]
And thats what the compiler is warning you
error: type mismatch;
found : List[List[Int]]
required: List[Int]
error: type mismatch;
found : List[List[Int]]
required: List[Int]
I hope the answer is helpful
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Isn't that given by the method declaration?
(List[List[(Int, Int)]], List[(Int, Int)], Int, Int)
– Dmitrii C.
Jul 3 at 7:11