Returning List[Double], Map[String, Double] from a list of Doubles - scala

I'm trying to return a tuple of a list and map. I've already gotten the list to compile correctly however I'm not sure how to use a map and list to get a map of the keys and values that match what's in my list. Here is what I have so far:
I've been able to achieve returning a list. However I need to return (List[Double], Map[String, Double])
def emulateSingleInstruction(stack: List[Double],
env: Map[String, Double],
ins: StackMachineInstruction): (List[Double], Map[String, Double]) = {
ins match{
case AddI => stack match{
case i1 :: i2 :: tail => (i1 + i2 :: tail, env)
case _ => throw new IllegalArgumentException()
}
//USE V1 and V2
case SubI => stack match{
case i1 :: i2 :: tail => (i1 - i2 :: tail, env)
case _ => throw new IllegalArgumentException()
}
case MultI => stack match{
case i1 :: i2 :: tail => (i1 * i2 :: tail, env)
case _ => throw new IllegalArgumentException()
}
//USE V1 and V2
case DivI => stack match{
case i1 :: i2 :: tail => (i1 / i2 :: tail, env)
case _ => throw new IllegalArgumentException()
}
case ExpI => stack match{
case Nil => throw new IllegalArgumentException()
case head :: tail => {
(scala.math.exp(head) :: tail,env)
}
}
case LogI => stack match{
case Nil => throw new IllegalArgumentException()
case head :: tail => {
if (head > 0){(scala.math.log(head) :: tail,env)}
else{ throw new IllegalArgumentException()}
}
}
case SinI => stack match{
case Nil => throw new IllegalArgumentException()
case head :: tail => {
(scala.math.sin(head) :: tail,env)
}
}
case CosI => stack match{
case Nil => throw new IllegalArgumentException()
case head :: tail => {
(scala.math.cos(head) :: tail,env)
}
}
case PushI(f) => (f :: stack,env)
case PopI => stack match{
case Nil => throw new IllegalArgumentException()
case i1 :: tail => {
(tail,env)
}
}
}
}

Since your example operation seems not to modify the environment but only the stack, I understand you are simply asking how to combine the new stack and the environment in the return value.
def emulateSingleInstruction(stack: List[Double],
env: Map[String, Double],
ins: StackMachineInstruction): (List[Double], Map[String, Double]) = {
val newStack = ins match {
case AddI => // your code. Looks good...
}
val newEnv = // expression that evaluates to the updated environment
(newStack, newEnv)
}

Related

What can blow out my laptop in tail recursion function?

I need to make function that group list into two lists by odd and even numbers of index, start from 1, not 0. I have a problem with infinity recursion, as I think, because time of doing second function is too much and my laptop is going to take the mars.
First function with simple recursion works fine, but the second, merge2, with tail recursion is blowing out my computer.
Here is the code:
// Simple recursion
def merge1(listA: List[String], listB: List[String]): List[String] = (listA, listB) match {
case (Nil, Nil) => Nil
case (head1 :: tail1, Nil) => head1 :: merge1(tail1, Nil)
case (Nil, head2 :: tail2) => head2 :: merge1(Nil, tail2)
case (head1 :: tail1, head2 :: tail2) => head1 + head2 :: merge1(tail1, tail2)
}
merge1 (List("a", "b", "c", "d"), List("e", "f", "g", "h", "i", "j"));
// Tail recursion
def merge2 (listA1: List[String], listB1: List[String]): List[String] = {
def merge2Helper(listA: List[String], listB: List[String], listACC: List[String]): List[String] =
(listA, listB) match {
case (Nil, Nil) => listACC
case (head1 :: tail1, Nil) => merge2Helper(tail1, listB, listACC ::: List(head1))
case (Nil, head2 :: tail2) => merge2Helper(tail2, listB, listACC ::: List(head2))
case (head1 :: tail1, head2 :: tail2) => merge2Helper(tail1, tail2, listACC ::: List(head1 + head2))
}
merge2Helper(listA1, listB1, Nil)
}
merge2 (List("a", "b", "c", "d"), List("e", "f", "g", "h", "i", "j"));
The 3rd case is wrong, it is passing the same list again that has just been processed.
It should be like this:
#tailrec def merge2Helper(listA: List[String], listB: List[String], listACC: List[String]): List[String] =
(listA, listB) match {
case (Nil, Nil) => listACC
case (head1 :: tail1, Nil) => merge2Helper(tail1, listB, listACC ::: List(head1))
case (Nil, head2 :: tail2) => merge2Helper(listA, tail2, listACC ::: List(head2))
case (head1 :: tail1, head2 :: tail2) => merge2Helper(tail1, tail2, listACC ::: List(head1 + head2))
}
You should also add the #tailrec annotation to hint the compiler you expect the function to be tail recursive (and fail if it is not), to ensure you don't end up in a stack overflow with long lists.

scala n-arity tree tail recursive evaluation

I have a Tree structure, which is more general than a binary tree structure
sealed trait Tree[+A]
case class Leaf[A](value: Terminal[A]) extends Tree[A]
case class Node[A](op: Function[A], branches: Tree[A]*) extends Tree[A]
As you see, it can have a arbitrary number of branches.
I'm trying to make an evaluation method to be tail recursive but i'm not being able to do it.
def evaluateTree[A](tree: Tree[A]): A = tree match {
case Leaf(terminal) => terminal.value
case Node(op: Function[A], args # _*) => op.operator((for (i <- args) yield evaluateTree(i)))
}
How can i save the stack manually?
If each Node can hold a different op then, no, I don't think tail recursion is possible.
If, on the other hand, you can feed all the Leaf.values to a single op then it might be possible.
def evaluateTree[A](tree: Tree[A]): A = {
#tailrec
def allValues(branches: Seq[Tree[A]], acc: Seq[A] = Seq()): Seq[A] =
if (branches.length < 1) acc
else branches.head match {
case Leaf(term) => allValues(branches.tail, term.value +: acc)
case Node(_, args: Seq[Tree[A]]) => allValues(branches.tail ++ args, acc)
}
tree match {
case Leaf(terminal) => terminal.value
case Node(op: Function[A], args: Seq[Tree[A]]) => op.operator(allValues(args))
}
}
I can't compile this as I don't have definitions for Terminal and Function, but it should be a reasonable outline of one approach to the problem.
Actually it was possible, using deep first search.
def evaluateTree[A](tree: Tree[A]): A = {
#tailrec
def evaluateWhile[C](l: List[Function[C]], arguments: List[List[C]], n_args: List[Int], f: Int => Boolean, acc: C): (List[Function[C]], List[List[C]], List[Int]) =
n_args match {
case h :: t if f(h) =>
evaluateWhile(l.tail, arguments.tail, n_args.tail, f, l.head.operator(arguments.head ::: List(acc)))
case h :: t =>
(l, (List(acc) ::: arguments.head) :: arguments.tail, List(n_args.head - 1) ::: n_args.tail)
case _ =>
(l, List(acc) :: arguments, n_args)
}
#tailrec
def DFS(toVisit: List[Tree[A]], visited: List[String] = Nil, operators: List[Function[A]] = Nil, arguments: List[List[A]] = Nil, n_args: List[Int] = Nil, debug: Int = 0): A = toVisit match {
case Leaf(id, terminal) :: tail if !visited.contains(id) => {
val (operators_to_pass, args_to_pass, n_args_to_pass) =
evaluateWhile[A](operators, arguments, n_args, x => x == 1, terminal.value)
DFS(toVisit.tail, visited ::: List(id), operators_to_pass, args_to_pass, n_args_to_pass, debug + 1)
}
case Node(id, op, args #_*) :: tail if !visited.contains(id) => {
DFS(args.toList ::: toVisit.tail, visited ::: List(id), op :: operators, List(Nil) ::: arguments, List(args.length ) ::: n_args, debug + 1)
}
case _ => arguments.flatten.head
}
DFS(List(tree))
}

Scala stack overflow error

I'm new to Scala and having trouble with this portion of code. I'm getting a stack overflow error on line 18 / 20, but I am not sure why.
def quicksort(list : List[Int]) : List[Int] = list match {
case Nil => List()
case x::Nil => List(x)
case x::xs => {
val lesserList = partitionLesser(list.tail, list(0))
val greaterList = partitionGreater(list.tail, list(0))
quicksort(lesserList ::: List(x) ::: greaterList)
}
}
def partitionLesser(list : List[Int], pivot : Int) : List[Int] = list match{
case Nil => List()
case x::Nil => List(x)
case x::xs => {
if(x <= pivot) { x :: partitionLesser(list.tail, pivot) }
else { partitionLesser(list.tail, pivot) }
}
}
def partitionGreater(list : List[Int], pivot : Int) : List[Int] = list match {
case Nil => List()
case x::Nil => List(x)
case x::xs => {
if(x > pivot) { x :: partitionGreater(list.tail, pivot) }
else { partitionLesser(list.tail, pivot)}
}
}
def quicksort(list : List[Int]) : List[Int] = list match {
case Nil => List()
case x::Nil => List(x)
case x::xs => {
val lesserList = partitionLesser(list.tail, list(0))
val greaterList = partitionGreater(list.tail, list(0))
// quicksort(lesserList ::: List(x) ::: greaterList)
quicksort(lesserList) ::: List(x) ::: quicksort(greaterList)
}
}

Return a different type according to an input parameter

Let's see an example (it's a naive example but sufficient to illustrate the problem).
def produce(l: List[Int]) : Any =
l match {
case List(x) => x
case List(x, y) => (x, y)
}
val client1 : Int = produce(List(1)).asInstanceOf[Int]
Drawback : client need to cast !
def produce2[A](l: List[Int])(f: List[Int] => A) = {
f(l)
}
val toOne = (l: List[Int]) => l.head
val toTwo = (l: List[Int]) => (l.head, l.tail.head)
val client2 : Int = produce2(List(1))(toOne)
Drawback : type safety, i.e. we can call toTwo with a singleton List.
Is there a better solution ?
If you only have two possible return values you could use Either:
def produce(l : List[Any]) : Either[Any, (Any, Any)] = l match {
case List(x) => Left(x)
case List(x, y) => Right((x, y))
}
If you don't want to create an Either, you could pass a function to transform each case:
def produce[A](l : List[Int])(sf: Int => A)(pf: (Int, Int) => A): A = l match {
case List(x) => sf(x)
case List(x, y) => pf(x, y)
}
Will this work?
def produce(l: List[Int]) = {
l match {
case List(x) => (x, None)
case List(x,y) => (x,y)
case Nil => (None, None)
}
}
or even better, to avoid match errors on lists longer than 2 elements:
def produce(l: List[Int]) =
l match {
case x :: Nil => (x, None)
case x :: xs => (x,xs.head)
case Nil => (None, None)
}

How to group messages by username?

A message class:
case class Message(username:String, content:String)
A message list:
val list = List(
Message("aaa", "111"),
Message("aaa","222"),
Message("bbb","333"),
Message("aaa", "444"),
Message("aaa", "555"))
How to group the messages by name and get the following result:
List( "aaa"-> List(Message("aaa","111"), Message("aaa","222")),
"bbb" -> List(Message("bbb","333")),
"aaa" -> List(Message("aaa","444"), Message("aaa", "555")) )
That means, if a user post several messages, then group them together, until another user posted. The order should be kept.
I can't think of an easy way to do this with the provided Seq methods, but you can write your own pretty concisely with a fold:
def contGroupBy[A, B](s: List[A])(p: A => B) = (List.empty[(B, List[A])] /: s) {
case (((k, xs) :: rest), y) if k == p(y) => (k, y :: xs) :: rest
case (acc, y) => (p(y), y :: Nil) :: acc
}.reverse.map { case (k, xs) => (k, xs.reverse) }
Now contGroupBy(list)(_.username) gives you what you want.
I tried to create such a code which works not only with Lists and can be written in operator notation. I came up with this:
object Grouper {
import collection.generic.CanBuildFrom
class GroupingCollection[A, C, CC[C]](ca: C)(implicit c2i: C => Iterable[A]) {
def groupBySep[B](f: A => B)(implicit
cbf: CanBuildFrom[C,(B, C),CC[(B,C)]],
cbfi: CanBuildFrom[C,A,C]
): CC[(B, C)] =
if (ca.isEmpty) cbf().result
else {
val iter = c2i(ca).iterator
val outer = cbf()
val inner = cbfi()
val head = iter.next()
var olda = f(head)
inner += head
for (a <- iter) {
val fa = f(a)
if (olda != fa) {
outer += olda -> inner.result
inner.clear()
}
inner += a
olda = fa
}
outer += olda -> inner.result
outer.result
}
}
implicit def GroupingCollection[A, C[A]](ca: C[A])(
implicit c2i: C[A] => Iterable[A]
): GroupingCollection[A, C[A], C] =
new GroupingCollection[A, C[A],C](ca)(c2i)
}
Can be used (with Lists, Seqs, Arrays, ...) as:
list groupBySep (_.username)
def group(lst: List[Message], out: List[(String, List[Message])] = Nil)
: List[(String, List[Message])] = lst match {
case Nil => out.reverse
case Message(u, c) :: xs =>
val (same, rest) = lst span (_.username == u)
group(rest, (u -> same) :: out)
}
Tail recursive version. Usage is simply group(list).
(List[Tuple2[String,List[Message]]]() /: list) {
case (head :: tail, msg) if msg.username == head._1 =>
(msg.username -> (msg :: head._2)) :: tail
case (xs, msg) =>
(msg.username -> List(msg)) :: xs
} map { t => t._1 -> t._2.reverse } reverse
Here's another method using pattern matching and tail recursion. Probably not as efficient as those above though due to the use of both takeWhile and dropWhile.
def groupBy(msgs: List[Message]): List[(String,List[Message])] = msgs match {
case Nil => List()
case head :: tail => (head.username ->
(head :: tail.takeWhile(m => m.username == head.username))) +:
groupBy(tail.dropWhile(m => m.username == head.username))
}