A "Simple' Scala question but took me long time to debug - scala

Please check the two pieces of script as above.
genComb4(lst) works since I put z <- genComb4(xs) before i <- 0 to x._2 in the for-comprehension; genComb(lst) does not work since I change the order of these two lines in for-comprehension.
It took me almost half day to find this bug, but I cannot explain it by myself. Could you tell me why this happened?
Thank you very much in advance.
// generate combinations
val nums = Vector(1, 2, 3)
val strs = Vector('a', 'b', 'c')
val lst: List[(Char, Int)] = strs.zip(nums).toList
def genComb4(lst: List[(Char, Int)]): List[List[(Char, Int)]] = lst match {
case Nil => List(List())
case x :: xs =>
for {
z <- genComb4(xs) // correct
i <- 0 to x._2 // correct
} yield ( (x._1, i) :: z)
}
genComb4(lst)
def genComb(lst: List[(Char, Int)]): List[List[(Char, Int)]] = lst match {
case Nil => List(List())
case x :: xs =>
for {
i <- (0 to x._2) // wrong
z <- genComb(xs) // wrong
} yield ( (x._1, i) :: z)
}
genComb(lst)

It's because of different types of container in for comprehension. When you start for-comprehension from line: i <- (0 to x._2) it's set type of result container as IndexedSeq but in case where first line is z <- genComb4(xs) the type of result container is List, take a look:
val x = 'a' -> 2
val indices: Seq[Int] = 0 to x._2
val combs: List[List[(Char, Int)]] = genComb4(List(x))
// indexed sequence
val indicesInFor: IndexedSeq[(Char, Int)] = for {
i <- 0 to x._2
} yield (x._1, i)
// list
val combsInFor: List[List[(Char, Int)]] = for {
z <- genComb4(List(x))
} yield z
so for make your second case is working, you should cast (0 to x._2).toList:
val indicesListInFor: List[(Char, Int)] = for {
i <- (0 to x._2).toList
} yield (x._1, i)
result code should be:
def genComb(lst: List[(Char, Int)]): List[List[(Char, Int)]] = lst match {
case Nil => List(List())
case x :: xs =>
for {
i <- (0 to x._2).toList
z <- genComb(xs)
} yield ( (x._1, i) :: z)
}
genComb(lst)
You should remember about type of starting line in for-comprehension and inheritance of scala collections. If next types in for-comprehension can't be converted by inheritance rules to the first expression line type you should take care about it by yourself.
Good practise is unwrap for-expression into flatMap, map and withFilter functions, then you will find miss-typing or something else faster.
useful links:
how does yield work, scala documentation
quick review of scala for-comprehensions
for-expressions, scala documentation

Related

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)
^
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)]],
rs : List[(Int,Int)],
d and n : Int
The compiler error appears as soon as I tell IntelliJ to send my code to the Scala console.
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:
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).
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.
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
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]
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
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]]
And thats what the compiler is warning you
error: type mismatch;
found : List[List[Int]]
required: List[Int]
I hope the answer is helpful

Drop a given number of positive items of a given list

Suppose I need a function List[Int] => Option[List[Int]] to drop exactly n elements of a given list if and only if all of them > 0. If the list size <= n the function should return None.
For instance:
def posn(n: Int): List[Int] => Option[List[Int]] = ???
val pos4: List[Int] => Option[List[Int]] = posn(4)
scala> pos4(Nil)
res18: Option[List[Int]] = None
scala> pos4(List(-1))
res19: Option[List[Int]] = None
scala> pos4(List(-1, 2, 3))
res20: Option[List[Int]] = None
scala> pos4(List(1, 2, 3))
res21: Option[List[Int]] = None
scala> pos4(List(1, 2, 3, 4, 5))
res22: Option[List[Int]] = Some(List(5))
scala> pos4(List(1, 2, 3, -4, 5))
res23: Option[List[Int]] = None
I am writing posn like that:
def posn(n: Int): List[Int] => Option[List[Int]] = xs =>
if (xs.size >= n && xs.take(n).forall(_ > 0)) Some(xs.drop(n)) else None
This function seems working bit it doesn't seem elegant and idiomatic. How would you re-write it ?
Here's an (arguably) more idiomatic implementation using Pattern Matching and a recursive call to posn - but I'm not sure it's preferable to your suggested implementation:
def posn(n: Int): List[Int] => Option[List[Int]] = xs => (n, xs) match {
case (0, _) => Some(xs) // stop if enough objects dropped
case (_, head :: tail) if head > 0 => posn(n - 1)(tail) // drop positive and move on
case _ => None // found a negative item or end of xs => "fail"
}
I don't know if there is an idiomatic or elegant way to do this. There seems to be no generic pattern that can be extracted from your logic, except what you have already done (using drop and take), so I don't believe you will find some more useful predefined method
However, you are traversing your list a few times, and this could be avoided:
def posn(n: Int): List[Int] => Option[List[Int]] = xs => {
val (head, tail) = xs.splitAt(n) //does take and drop in one run
if (head.lengthCompare(n) == 0 && head.forall(_ > 0)) Some(tail) // lengthCompare does not compute the whole length if there is no need to
else None
}
This is still not perfect, and more verbose than your version.
You could also do all of it at once, with tail recursion (here assuming n>=0):
def posn(n: Int): List[Int] => Option[List[Int]] = xs =>
if (n == 0) Some(xs)
else if (xs.isEmpty || xs.head <= 0) None
else posn(n - 1)(xs.tail)
This would be more efficient if List was naively implemented, but I really doubt you will see any improvement.
I would write a generic version and use that to define posn:
def dropWhen[T](n: Int, p: T => Boolean, l: List[T]): Option[List[T]] = {
val (f, s) = l.splitAt(n)
if (f.length >= n && f.forall(p)) { Some(s) } else { None }
}
def posn(n: Int): List[Int] => Option[List[Int]] = l => dropWhen(n, (i : Int) => i > 0, l)
Note this method scans the prefix of length n twice
Another (non-recursive) alternative: use zipWithIndex and dropWhile to drop the first N positive numbers, and then check head to see whether the first remaining item is exactly at position n: if it is, we got what we want, otherwise we can return None:
def posn(n: Int): List[Int] => Option[List[Int]] = xs =>
Some(xs.zipWithIndex.dropWhile { case (v, i) => v > 0 && i < n })
.find(_.headOption.exists(_._2 == n)) // first index should be n
.map(_.map(_._1)) // remove indices

Pattern Matching Function Call in Scala

I am originally posting the question on CodeReview but it seems to be not fitted there. I'll reask here. Please tell me if it's also not fit here, and where should I post this kind of question. Thanks.
I am a newbie in Scala and functional programming. I want to call a function several times, with combination of parameters based on two variables. Basically, What I am doing right now is this:
def someFunction(a: Int, b: Int): Future[Int] = ???
val value1 = true
val value2 = false
(value1, value2) match {
case (true, true) =>
val res1 = someFunction(0, 0)
val res2 = someFunction(0, 1)
val res3 = someFunction(1, 0)
val res4 = someFunction(1, 1)
for {
r1 <- res1
r2 <- res2
r3 <- res3
r4 <- res4
} yield r1 + r2 + r3 + r4
case (true, false) =>
val res1 = someFunction(0, 0)
val res2 = someFunction(1, 0)
for {
r1 <- res1
r2 <- res2
} yield r1 + r2
case (false, true) =>
val res1 = someFunction(0, 0)
val res2 = someFunction(0, 1)
for {
r1 <- res1
r2 <- res2
} yield r1 + r2
case (false, false) =>
for { r1 <- someFunction(0, 0) } yield r1
}
I am not satisfied with the above code as it is repetitive and hard to read / maintain. Is there any better way I could do this? I've tried to search on how to combine function by pattern matching value like this, but finds nothing to work with. Looks like I don't know the right term for this.
Any help would be appreciated, and feel free to change the title if there's a better wording.
Thanks before :)
An easier way could be to pregenerate a sequence of argument tuples:
val arguments = for {
arg1 <- 0 to (if (value1) 1 else 0)
arg2 <- 0 to (if (value2) 1 else 0)
} yield (arg1, arg2)
Then you can combine function executions on the arguments with Future.traverse to get a Future of the sequence of results, and then sum the results:
Future.traverse(arguments)(Function.tupled(someFunction)).map(_.sum)
I think this should solve your problem:
def someFunction(x: Int, y: Int): Future[Int] = ???
def someFunctionTupled: ((Int, Int)) => Future[Int] = (someFunction _).tupled // Same as someFunction but you can pass in a tuple here
def genParamList(b: Boolean) = if (b)
List(0, 1)
else
List(0)
val value1 = true
val value2 = false
val l1 = genParamList(value1)
val l2 = genParamList(value2)
// Combine the two parameter lists by constructing the cartesian product
val allParams = l1.foldLeft(List[(Int, Int)]()){
case (acc, elem) => acc ++ l2.map((elem, _))
}
allParams.map((someFunction _).tupled).sum
The above code will result in a Future[Int] which is the sum of all results of someFunction applied to the elements of the allParams list.

Using for comprehension in Scala

def combinations(occurrences: List[(Char,Int)]): List[List[(Char,Int)]] = occurrences match {
case Nil => Nil
case x :: xs => for(z <- combinations(xs); y <- occ(x)) yield (y :: z)
}
def occ(e: (Char, Int)): List[(Char, Int)] = (for(i <- 0 to e._2) yield (e._1, i)).toList
Hi,
I can't find any flaw in the above snippet but it still giving me List() for any input.
Well, I think you are pretty close to the answer. The most important thing is to consider what is the right return value in case of Nil.
def combinations(occurrences: Occurrences): List[Occurrences] = occurrences match {
case Nil => List(List())
case x :: xs =>
for {
z <- combinations(xs)
n <- 0 to x._2
} yield (if (n == 0) z else (x._1, n) :: z)
}
You're first for comprehension will always yield a Nil at the end of your recursion which will force the rest of your recursion to be Nil. Here's a slightly modified version that works, though it gives a List[(Char, Int)] instead of a List[List[(Char, Int)]]:
def combinations(occurrences: List[(Char,Int)]): List[(Char,Int)] = occurrences match {
case Nil => Nil
case x :: xs => (for { z <- combinations(xs) } yield z) ::: occ(x)
}
If the first part of your for comprehension returns Nil, then it won't evaluate the rest of it and will just return Nil. I've changed things around a bit, so now even if it does evaluate to Nil, it will be combined with the results of occ.
def combinations(occurrences: List[(Char,Int)]): List[List[(Char,Int)]] = occurrences match {
case Nil => List(List())
case x :: xs => for(z <- combinations(xs); y <- occ(x)) yield (y :: z)
}
def occ(e: (Char, Int)): List[(Char, Int)] = (for(i <- 0 to e._2) yield (e._1, i)).toList
This has solved my problem!!!

Scala Get First and Last elements of List using Pattern Matching

I am doing a pattern matching on a list. Is there anyway I can access the first and last element of the list to compare?
I want to do something like..
case List(x, _*, y) if(x == y) => true
or
case x :: _* :: y =>
or something similar...
where x and y are first and last elements of the list..
How can I do that.. any Ideas?
Use the standard :+ and +: extractors from the scala.collection package
ORIGINAL ANSWER
Define a custom extractor object.
object :+ {
def unapply[A](l: List[A]): Option[(List[A], A)] = {
if(l.isEmpty)
None
else
Some(l.init, l.last)
}
}
Can be used as:
val first :: (l :+ last) = List(3, 89, 11, 29, 90)
println(first + " " + l + " " + last) // prints 3 List(89, 11, 29) 90
(For your case: case x :: (_ :+ y) if(x == y) => true)
In case you missed the obvious:
case list # (head :: tail) if head == list.last => true
The head::tail part is there so you don’t match on the empty list.
simply:
case head +: _ :+ last =>
for example:
scala> val items = Seq("ham", "spam", "eggs")
items: Seq[String] = List(ham, spam, eggs)
scala> items match {
| case head +: _ :+ last => Some((head, last))
| case List(head) => Some((head, head))
| case _ => None
| }
res0: Option[(String, String)] = Some((ham,eggs))
Lets understand the concept related to this question, there is a difference between '::', '+:' and ':+':
1st Operator:
'::' - It is right associative operator which works specially for lists
scala> val a :: b :: c = List(1,2,3,4)
a: Int = 1
b: Int = 2
c: List[Int] = List(3, 4)
2nd Operator:
'+:' - It is also right associative operator but it works on seq which is more general than just list.
scala> val a +: b +: c = List(1,2,3,4)
a: Int = 1
b: Int = 2
c: List[Int] = List(3, 4)
3rd Operator:
':+' - It is also left associative operator but it works on seq which is more general than just list
scala> val a :+ b :+ c = List(1,2,3,4)
a: List[Int] = List(1, 2)
b: Int = 3
c: Int = 4
The associativity of an operator is determined by the operator’s last character. Operators ending in a colon ‘:’ are right-associative. All other operators are left-associative.
A left-associative binary operation e1;op;e2 is interpreted as e1.op(e2)
If op is right-associative, the same operation is interpreted as { val x=e1; e2.op(x) }, where x is a fresh name.
Now comes answer for your question:
So now if you need to get first and last element from the list, please use following code
scala> val firstElement +: b :+ lastElement = List(1,2,3,4)
firstElement: Int = 1
b: List[Int] = List(2, 3)
lastElement: Int = 4