When running this piece of code:
object P01 {
#annotation.tailrec
final def lastRecursive[A] (ls:List[A]):A = {
def lr[A] (l:List[A]):A = l match {
case h :: Nil => h
case _ :: tail => lr(tail)
case _ => throw new NoSuchElementException
}
lr(ls)
}
}
P01.lastRecursive(List(1,2,3))
,in scala 2.10.2 REPL, I get the following error:
scala> :9: error: #tailrec annotated method contains no recursive calls
final def lastRecursive[A] (ls:List[A]):A = {
^
Please help, I don't understand what am I doing wrong.
lastRecursive isn't tail recursive but lr is. This worked for me:
object P01 {
final def lastRecursive[A] (ls:List[A]):A = {
#annotation.tailrec
def lr[A] (l:List[A]):A = l match {
case h :: Nil => h
case _ :: tail => lr(tail)
case _ => throw new NoSuchElementException
}
lr(ls)
}
}
Related
I am having problems with this function. I need to process more than 1 million records, but this crashes. Looks like just works with thousands of records and throws a StackOverflowError for a larger list. Any suggestions?
def split(list: List[(Pair, Boolean)]): List[List[Pair]] = list match {
case Nil => Nil
case head :: tail => {
val (l1, l2) = tail.span(!_._2)
(head :: l1).map(_._1) :: split(l2)
}
}
Your program will throw a StackOverflow exception:
Exception in thread "main" java.lang.StackOverflowError
at scala.collection.immutable.List.map(List.scala:283)
The reason is very simple because your method is not tail-recursive
If you annotate it with #tailrec, it won't compile:
#tailrec
def split(list: List[(Pair, Boolean)]): List[List[Pair]] = list match {
case Nil => Nil
case head :: tail => {
val (l1, l2) = tail.span(!_._2)
(head :: l1).map(_._1) :: split(l2)
}
}
The solution is to make your recusion tailrec, or use some kind of loop instead
You could try something like this:
#tailrec
def split(list: List[(Pair, Boolean)], accumulator: List[List[Pair]] = List[List[Pair]]()): List[List[Pair]] = list match {
case Nil => accumulator
case head :: tail => {
val (l1, l2) = tail.span(!_._2)
split(l2, (head :: l1).map(_._1)::accumulator)
}
}
I want to get value from function that passed as parameter and returns Option[Int], after that if I have None throw an exception and in any other case return value
I tried to do like this:
def foo[T](f: T => Option[Int]) = {
def helper(x: T) = f(x)
val res = helper _
res match {
case None => throw new Exception()
case Some(z) => z
}
I call it like this:
val test = foo[String](myFunction(_))
test("Some string")
I have compilation error with mismatched types in match section (Some[A] passed - [T] => Option[Int] required)
As I understood res variable is reference to the function and I cannot match it with optional either call get\gerOrElse methods.
Moreover I probably just dont get how the underscore works and doing something really wrong, I'm using it here to pass a something as parameter to function f, can you explain me where I made a mistake?
helper is a method taking a T and returning an Option[Int].
res is a function T => Option[Int].
Difference between method and function in Scala
You can't match a function T => Option[Int] with None or Some(z).
You should have an Option[Int] (for example the function applied to some T) to make such matching.
Probably you would like to have
def foo[T](f: T => Option[Int]) = {
def helper(x: T) = f(x)
val res = helper _
(t: T) => res(t) match {
case None => throw new Exception()
case Some(z) => z
}
}
or just
def foo[T](f: T => Option[Int]): T => Int = {
t => f(t) match {
case None => throw new Exception()
case Some(z) => z
}
}
or
def foo[T](f: T => Option[Int]): T => Int =
t => f(t).getOrElse(throw new Exception())
I'm writing a recursive function which returns False or a List of values.
def parse(chars: List[Char]): Either[List[Char], Boolean] = {
if (chars.length == 1)
chars
else {
val head = chars.head
val tail = parse(chars.tail)
tail match {
case Left(l) => {
if (are_equal(head, tail.head))
head :: tail
else if (are_cancelled(head, tail.head))
tail.tail
else
false
}
case Right(b) => false
}
}
}
I'm getting error: value head is not a member of Either[List[Char],Boolean], but head method should only be used after matching the list.
The pattern match tail match { ... } doesn't magically change the type of the value you're matching on. tail is still an Either and Either doesn't have a member head. But l is a List, so replace tail.head with l.head and so on.
You can try inserting explicit type annotation to make things clearer.
Your return types are also wrong in a few places. Here's a version that's closer to compiling:
def parse(chars: List[Char]): Either[List[Char], Boolean] = {
if (chars.length == 1) {
Left(chars)
} else {
val head = chars.head
val tail = parse(chars.tail)
tail match {
case Left(l) =>
if (are_equal(head, l.head))
Left(head :: l)
else if (are_cancelled(head, l.head))
Left(l.tail)
else
Right(false)
case Right(b) => Right(false)
}
}
}
In Scala we have a by-name-parameters where we can write
def foo[T](f: => T):T = {
f // invokes f
}
// use as:
foo(println("hello"))
I now want to do the same with an array of methods, that is I want to use them as:
def foo[T](f:Array[ => T]):T = { // does not work
f(0) // invokes f(0) // does not work
}
foo(println("hi"), println("hello")) // does not work
Is there any way to do what I want? The best I have come up with is:
def foo[T](f:() => T *):T = {
f(0)() // invokes f(0)
}
// use as:
foo(() => println("hi"), () => println("hello"))
or
def foo[T](f:Array[() => T]):T = {
f(0)() // invokes f(0)
}
// use as:
foo(Array(() => println("hi"), () => println("hello")))
EDIT: The proposed SIP-24 is not very useful as pointed out by Seth Tisue in a comment to this answer.
An example where this will be problematic is the following code of a utility function trycatch:
type unitToT[T] = ()=>T
def trycatch[T](list:unitToT[T] *):T = list.size match {
case i if i > 1 =>
try list.head()
catch { case t:Any => trycatch(list.tail: _*) }
case 1 => list(0)()
case _ => throw new Exception("call list must be non-empty")
}
Here trycatch takes a list of methods of type ()=>T and applies each element successively until it succeeds or the end is reached.
Now suppose I have two methods:
def getYahooRate(currencyA:String, currencyB:String):Double = ???
and
def getGoogleRate(currencyA:String, currencyB:String):Double = ???
that convert one unit of currencyA to currencyB and output Double.
I use trycatch as:
val usdEuroRate = trycatch(() => getYahooRate("USD", "EUR"),
() => getGoogleRate("USD", "EUR"))
I would have preferred:
val usdEuroRate = trycatch(getYahooRate("USD", "EUR"),
getGoogleRate("USD", "EUR")) // does not work
In the example above, I would like getGoogleRate("USD", "EUR") to be invoked only if getYahooRate("USD", "EUR") throws an exception. This is not the intended behavior of SIP-24.
Here is a solution, although with a few restrictions compared to direct call-by-name:
import scala.util.control.NonFatal
object Main extends App {
implicit class Attempt[+A](f: => A) {
def apply(): A = f
}
def tryCatch[T](attempts: Attempt[T]*): T = attempts.toList match {
case a :: b :: rest =>
try a()
catch {
case NonFatal(e) =>
tryCatch(b :: rest: _*)
}
case a :: Nil =>
a()
case Nil => throw new Exception("call list must be non-empty")
}
def a = println("Hi")
def b: Unit = sys.error("one")
def c = println("bye")
tryCatch(a, b, c)
def d: Int = sys.error("two")
def e = { println("here"); 45 }
def f = println("not here")
val result = tryCatch(d, e, f)
println("Result is " + result)
}
The restrictions are:
Using a block as an argument won't work; only the last expression of the block will be wrapped in an Attempt.
If the expression is of type Nothing (e.g., if b and d weren't annotated), the conversion to Attempt is not inserted since Nothing is a subtype of every type, including Attempt. Presumably the same would apply for an expression of type Null.
As of Scala 2.11.7, the answer is no. However, there is SIP-24, so in some future version your f: => T* version may be possible.
Code to determine the lat element of a list, using pattern matching:
#tailrec
def last_rec[A](list : List[A]) : A = {
list match {
case (x :: Nil) => x
case (_ :: xs) => last_rec(xs)
case Nil => throw new NoSuchElementException
}
}
I want to compile the code, I am getting "yelled" by the compiler:
PS D:\workspace\scala\P99> scalac .\P01.scala
.\P01.scala:18: error: could not optimize #tailrec annotated method last2: it contains a recursive call not in tail position
case Nil => throw new NoSuchElementException
^
one error found
If I remove the #tailrec annotation - the code compiles . How can I modify the code in order to do the tail rec optimization ?
You got a typo their. Your method is called last_rec and you are calling last which is clearly undefined. So just rename it to last. And by the way you should return Option[A] instead of A. That way you can return None when nothing is found instead of throwing the ugly NoSuchElementException.
After removing the typo and adding agilesteel's suggestion:
#tailrec
def last_rec[A](list : List[A]) : Option[A] = {
list match {
case (x :: Nil) => Some(x)
case Nil => None
case (_ :: xs) => last_rec(xs)
}
}
In this case I would do what agilesteel suggested.
However, if you really wanted to throw an exception (in another different use case), you could do it in a statically typed way:
#tailrec
def last_rec[A](list : List[A]) : Either[NoSuchElementException,A] = {
list match {
case (x :: Nil) => Right(x)
case (_ :: xs) => last_rec(xs)
case Nil => Left(new NoSuchElementException)
}
}
where later you could:
last_rec(Nil) match {
case Right(s) => println("Got a value")
case Left(e) => println("Got an exception")
}