I know that parametric polymorphism is what actually works, but I'm curious why using Any in it's place does not. For example how is the first function
def len[T] (l:List[T]):Int =
l match {
case Nil => 0
case _ :: t => 1 + len(t)
}
different from this one?
def len (l:List[Any]):Int =
l match {
case Nil => 0
case _ :: t => 1 + len(t)
}
What do you mean it doesn't work? This seems fine:
len(List('a,'b,'c))
// res0: Int = 3
Your in your example, there really isn't a difference, since you're not actually using the contents of the list for anything, but imagine a slightly different function:
def second[T](l: List[T]): Option[T] =
l match {
case Nil => None
case _ :: Nil => None
case _ :: x :: _ => Some(x)
}
println(second(List(1,2,3)).map(_ + 5)) // Some(7)
println(second(List(List('a,'b,'c), List('d,'e))).map(_.head)) // Some('d)
If you tried this with Any, you wouldn't be able to get anything except Option[Any] in return, so the compiler wouldn't let you do anything useful with the result (like add it to an Int or call .head, as in the examples, respectively).
In this case there really isn't a difference, because you aren't relying on the contained type at all, just the structure of List itself. It doesn't matter what T is, the length will be the same either way.
The type parameter would be important if you wanted to return another List[T]. For example:
def takeEveryOther[T](l: List[T]): List[T] =
l.zipWithIndex.collect { case (a, i) if(i % 2 == 0) => a }
Related
How to write an early-return piece of code in scala with no returns/breaks?
For example
for i in 0..10000000
if expensive_operation(i)
return i
return -1
How about
input.find(expensiveOperation).getOrElse(-1)
You can use dropWhile
Here an example:
Seq(2,6,8,3,5).dropWhile(_ % 2 == 0).headOption.getOrElse(default = -1) // -> 8
And here you find more scala-takewhile-example
With your example
(0 to 10000000).dropWhile(!expensive_operation(_)).headOption.getOrElse(default = -1)`
Since you asked for intuition to solve this problem generically. Let me start from the basis.
Scala is (between other things) a functional programming language, as such there is a very important concept for us. And it is that we write programs by composing expressions rather than statements.
Thus, the concept of return value for us means the evaluation of an expression.
(Note this is related to the concept of referential transparency).
val a = expr // a is bounded to the evaluation of expr,
val b = (a, a) // and they are interchangeable, thus b === (expr, expr)
How this relates to your question. In the sense that we really do not have control structures but complex expressions. For example an if
val a = if (expr) exprA else exprB // if itself is an expression, that returns other expressions.
Thus instead of doing something like this:
def foo(a: Int): Int =
if (a != 0) {
val b = a * a
return b
}
return -1
We would do something like:
def foo(a: Int): Int =
if (a != 0)
a * a
else
-1
Because we can bound all the if expression itself as the body of foo.
Now, returning to your specific question. How can we early return a cycle?
The answer is, you can't, at least not without mutations. But, you can use a higher concept, instead of iterating, you can traverse something. And you can do that using recursion.
Thus, let's implement ourselves the find proposed by #Thilo, as a tail-recursive function.
(It is very important that the function is recursive by tail, so the compiler optimizes it as something equivalent to a while loop, that way we will not blow up the stack).
def find(start: Int, end: Int, step: Int = 1)(predicate: Int => Boolean): Option[Int] = {
#annotation.tailrec
def loop(current: Int): Option[Int] =
if (current == end)
None // Base case.
else if (predicate(current))
Some(current) // Early return.
else
loop(current + step) // Recursive step.
loop(current = start)
}
find(0, 10000)(_ == 10)
// res: Option[Int] = Some(10)
Or we may generalize this a little bit more, let's implement find for Lists of any kind of elements.
def find[T](list: List[T])(predicate: T => Boolean): Option[T] = {
#annotation.tailrec
def loop(remaining: List[T]): Option[T] =
remaining match {
case Nil => None
case t :: _ if (predicate(t)) => Some(t)
case _ :: tail => loop(remaining = tail)
}
loop(remaining = list)
}
This is not necessarily the best solution from a practical perspective but I still wanted to add it for educational purposes:
import scala.annotation.tailrec
def expensiveOperation(i: Int): Boolean = ???
#tailrec
def findFirstBy[T](f: (T) => Boolean)(xs: Seq[T]): Option[T] = {
xs match {
case Seq() => None
case Seq(head, _*) if f(head) => Some(head)
case Seq(_, tail#_*) => findFirstBy(f)(tail)
}
}
val result = findFirstBy(expensiveOperation)(Range(0, 10000000)).getOrElse(-1)
Please prefer collections methods (dropWhile, find, ...) in your production code.
There a lot of better answer here but I think a 'while' could work just fine in that situation.
So, this code
for i in 0..10000000
if expensive_operation(i)
return i
return -1
could be rewritten as
var i = 0
var result = false
while(!result && i<(10000000-1)) {
i = i+1
result = expensive_operation(i)
}
After the 'while' the variable 'result' will tell if it succeed or not.
I am trying to write a recursive function in scala that takes in a list of Strings and returns a list with alternating elements from original list:
For example:
List a = {"a","b","c"}
List b = {"a","c"}
the head should always be included.
def removeAlt(list:List[String], str:String):List[String]=lst match{
case Nil=> List()
case => head::tail
if(head == true)
removeAlternating(list,head)
else
head::removeAlternating(list,head)
I get a stack overflow error.
I understand that the code is incorrect but I am trying to understand the logic on how to accomplish this with only recursion and no built in classes.
def remove[A](xs:List[A]):List[A] = xs match {
case Nil => Nil
case x::Nil => List(x)
case x::y::t => x :: remove(t)
}
if the list is empty, return a empty list.
If we're at the last element of the list, return that.
Otherwise, there must be two or more elements. Add to the first element the alternate elements of the rest of the list (and omit the second element)
Great exercise. This is what I came up with. It is not super optimized or anything:
def altList[T](rest: List[T], skip: Boolean): List[T] = {
rest match {
case Nil => Nil
case a :: tail if skip == false => a :: altList(tail, true)
case a :: tail if skip == true => altList(tail, false)
}
}
A bit shorter alternative:
def remove[A](xs:List[A]):List[A] = xs match {
case x::_::t => x :: remove(t)
case _ => xs
}
UPDATE
What is not so good with the above approach is eventual stack overflow for long lists, so I would suggest tail recursion:
import scala.annotation.tailrec
def remove[A](xs:List[A]):List[A] = {
#tailrec
def remove_r(xs:List[A], ys:List[A]):List[A] = xs match {
case x::_::t => remove_r(t, x::ys)
case _ => xs ++ ys
}
remove_r(xs, Nil).reverse
}
I have seen this question How to sort a list in Scala by two fields?
This is similar but not a duplicate.
I can easily sort a List[DataPoint] using the answer from the earlier question:
case class DataPoint(keys: List[String], value: Double)
listOfDataPoints.sortBy(point => (point.keys(0), point.keys(1)))
However I don't know the number of items in keys. What I do know is that every DataPoint in a given list will have the same number of keys, so there is never a case of sorting List("a") and List("a", "b").
So how can I sort the list by an unknown number of keys?
What you want to do is
datapoints.sortby(_.keys)
This evidently doesn't work. When we take a look at the signature of sortby, it becomes evident why it doesn't work:
sortBy[B](f: (A) ⇒ B)(implicit ord: math.Ordering[B]): List[A]
Your B is a List[String] and you don't have an instance of Ordering[List[String]]. So what do we do? We supply one!
What we need to do for that is implement the method
def compare(x: T, y: T): Int
We want to compare on the following:
If the first key is different between two items, then use that key for sorting
Otherwise, sort by the rest of the List
If one of the lists is empty, the other one comes first[1]
Our T's here are Strings, but all we need for the T's is to be comparable for this, so we can be a little more general.
def listOrdering[T](implicit ord: Ordering[T]): Ordering[List[T]] = new Ordering[List[T]] {
def compare(x: List[T], y: List[T]): Int = {
(x, y) match {
case (Nil, Nil) => 0 //both empty => equal
case (Nil, _) => -1 //one of the two empty => empty is the smallest
case (_, Nil) => 1 //one of the two empty => empty is the smallest
case (xhead :: xtail, yhead :: ytail) => {
val headdiff = ord.compare(xhead, yhead)
if (headdiff == 0) compare(xtail, ytail) //recursively compare the tails if equivalent
else (headdiff ) //otherwise, the difference in the heads
}
}
}
}
now we can supply the ordering to the sortby method explicitly:
datapoints.sortby(_.keys)(listOrdering)
or provide them in implicit scope
[1]: you indicated this never happens, so any choice is good enough
You could define your own Ordering[List[String]]. For example, you could define:
class ListOrdering[A](implicit aOrd: math.Ordering[A]) extends Ordering[List[A]] {
def compare(a1: List[A], a2: List[A]) = (a1, a2) match {
case (Nil, _) => if (a2.isEmpty) 0 else -1
case (_, Nil) => 1
case (h1 :: t1, h2 :: t2) => if (aOrd.compare(h1, h2) == 0) compare(t1, t2) else aOrd.compare(h1, h2)
}
}
Then making the following available somewhere in scope:
implicit val listOrd = new ListOrdering[String]
you can write:
dps.sortBy(_.keys)
and it should work.
Note that my definition of ListOrdering is generalised to be useable for any type A with an implicit Ordering[A] in scope, and can handle lists of variable length (even though you say that in your case your key lists are always the same length).
I have a function that as a parameter takes an object and if it is of the correct type I need to access the last element in an Option[List[Int]]. I have a working solution but it seems clumsy. In the case that there are not any items in obj.listOfThings I will need to have i have the value 0. Is there a better way to achieve this?
val i = foo match {
case obj: Bar =>
obj.listOfInts match {
case Some(ints) =>
ints.last
case _ =>
0
}
case _ =>
0
}
Technically it could return an Option[Int]. I'm still pretty new to Scala and would like to learn better approaches to this sort of problems.
In your case initially it seems that what Ende Neu suggested is the right way to go:
val i = foo match {
case obj: Bar =>
obj.listOfInts.map(_.last /* This throws an exception when the list is empty*/).getOrElse(0)
case _ =>
0
}
But if you look into it you'll see that you have a bug in your code, in the case that that obj.listOfInts is Some(Nil), because in that case you get a NoSuchElementException for trying to call last on an empty List.
Try this code with foo = Bar(Some(Nil)) and see for yourself.
When you use Option[List] think very carefully if this is what you want.
Usually after some thinking you will scrap the Option and just stay with a List because the Option serves no purpose.
I worked with many developers who misuse Option[List] because of not understanding the similarities between Nil and None and usually the 'None' case ends up playing the same role as Some(Nil)
So you end up having to do this:
optionalList match {
case None => // do something
case Some(list) =>
list match {
case Nil => // do the same thing
case head::tail => // do other stuff
}
}
As you can see the None case and the Some(Nil) case are basically the same.
To fix your bug you should do:
case class Bar(listOfInts: Option[List[Int]])
val i = foo match {
case Bar(Some(list)) if list != Nil => list.last
case _ => 0
}
You probably want to use flatMap and lastOption here:
obj.listOfInts.flatMap(_.lastOption)
In case listOfInts is None, or it is Some(Nil), this will return None. Otherwise it will return the last element. If you want to return 0 instead of None, just use getOrElse:
obj.listOfInts.flatMap(_.lastOption).getOrElse(0)
If you wanted to use a match, you could do:
obj.listOfInts match {
case Some(list#(hd::tl)) => list.last
case _ => 0
}
Here, the hd::tl guarantees that list is not empty. Another option is use a conditional match:
obj.listOfInts match {
case Some(list) if list.nonEmpty => list.last
case _ => 0
}
Or to match the None and Some(Nil) cases first:
obj.listOfInts match {
case None | Some(Nil) => 0
case Some(list) => list.last
}
As suggested in the comments, I think the best way to go is:
val i = foo match {
case obj: Bar => obj.listOfInts.map(_.last).getOrElse(0)
case _ => 0
}
More concise way including the instanceof:
scala> case class B(is: Option[List[Int]])
defined class B
scala> def f(x: Any) = Option(x) collect { case b: B => b.is flatMap (_.lastOption) } flatten
f: (x: Any)Option[Int]
scala> f(B(Option(5 to 7 toList)))
res0: Option[Int] = Some(7)
or
scala> import PartialFunction.{ condOpt => when }
import PartialFunction.{condOpt=>when}
scala> def g(x: Any) = when(x) { case b: B => b.is flatMap (_.lastOption) } flatten
g: (x: Any)Option[Int]
scala> g(B(Option(5 to 7 toList)))
res1: Option[Int] = Some(7)
It's probably worth asking why you lost static type info, that you need to pattern match.
I'm looking to match a sequence within a sequence like either in ex 1 or ex 2;
List(1, 2, 3, 4) match {
case 1 :: List(_*) :: 4 :: tail => // Ex 1
case 1 :: (seq : List[Int]) :: 4 :: tail => // Ex 2
case _ =>
}
This is a variant to the fixed length sequence pattern _*. Like the _*, I don't care about the content of the inner pattern, but it is important that the length can vary and that the pattern is surrounded by a prefix (such as the 1 above) and a suffix (like the 4).
My question is if any of you have a trick to do this by some crafty unapply magic or if you'd just iterate the list to search for the sequence manually.
Thanks in advance! :-)
This is really outside the scope of what pattern matching is supposed to be used for. Even if you could finagle a set of custom unapply methods to do what you wanted, it wouldn't be apparent whether matching was greedy or not, etc..
However, if you really want to, you can proceed as follows (for example):
import scala.collection.SeqLike
class Decon[A](a0: A, a1: A) {
def unapply[C <: SeqLike[A, C]](xs: C with SeqLike[A, C]): Option[(C, C)] = {
xs.span(_ != a1) match {
case (a0 +: pre, a1 +: post) => Some((pre,post))
case _ => None
}
}
}
val Dc = new Decon(1,4)
scala> List(1,2,3,4,5) match { case Dc(pre, post) => (pre, post); case _ => (Nil, Nil) }
res1: (List[Int], List[Int]) = (List(2, 3),List(5))
Separating the specification of the fixed elements 1 and 4 from the match is necessary; otherwise the normal algorithm would ask the unapply to return values without any knowledge of what was being sought, and then would test to make sure they were correct.
You could do something like this:
List(1,2,3,4) match {
case 1 :: tail if tail.last == 4 => println("Found it!")
}
But if you check the implementation of last in LinearSeqOptimized:
def last: A = {
if (isEmpty) throw new NoSuchElementException
var these = this
var nx = these.tail
while (!nx.isEmpty) {
these = nx
nx = nx.tail
}
these.head
}
It is iterating indeed. This is because List inherits from LinearSeq which are optimized to provide efficient head and tail operations. For what you want to do, it is better to use an IndexedSeq implementation like Vector which has an optimized length operation, used in last:
override /*TraversableLike*/ def last: A = {
if (isEmpty) throw new UnsupportedOperationException("empty.last")
apply(length-1)
}
So you could do something like this:
Vector(1,2,3,4) match {
case v if v.head == 1 && v.last == 4 => println("Found it!")
}