I wrote a method to calculate the maximum depth of a binary tree.
I would like to write a tail recursive method.
I thought of using lists, but I didn't find solutions
This is my method that is not tail recursive:
def depth: Int = {
def iter(f: FormulaWff): Int = f match {
case Var(_) => 0
case Not(e1) => 1 + iter(e1)
case And(e1, e2) => 1 + Math.max(iter(e1), iter(e2))
case Or(e1, e2) => 1 + Math.max(iter(e1), iter(e2))
case Implies(e1, e2) => 1 + Math.max(iter(e1), iter(e2))
}
iter(this)
}
Try
import scala.util.control.TailCalls.{TailRec, done, tailcall}
trait FormulaWff {
def depth: Int = {
def iter(f: FormulaWff): TailRec[Int] = {
def hlp(e1: FormulaWff, e2: FormulaWff): TailRec[Int] = for {
x <- tailcall(iter(e1))
y <- tailcall(iter(e2))
} yield 1 + Math.max(x, y)
f match {
case Var(_) => done(0)
case Not(e1) => for {
x <- tailcall(iter(e1))
} yield 1 + x
case And(e1, e2) => hlp(e1, e2)
case Or(e1, e2) => hlp(e1, e2)
case Implies(e1, e2) => hlp(e1, e2)
}
}
iter(this).result
}
}
case class Var(s: String) extends FormulaWff
case class Not(e: FormulaWff) extends FormulaWff
case class And(e1: FormulaWff, e2: FormulaWff) extends FormulaWff
case class Or(e1: FormulaWff, e2: FormulaWff) extends FormulaWff
case class Implies(e1: FormulaWff, e2: FormulaWff) extends FormulaWff
Direct solution
sealed trait FormulaWff
final case class Var(s: String) extends FormulaWff
final case class Not(e: FormulaWff) extends FormulaWff
final case class And(e1: FormulaWff, e2: FormulaWff) extends FormulaWff
final case class Or(e1: FormulaWff, e2: FormulaWff) extends FormulaWff
final case class Implies(e1: FormulaWff, e2: FormulaWff) extends FormulaWff
sealed trait Result
case object NotExpanded extends Result
case object Expanded extends Result
final case class Calculated(value: Int) extends Result
final case class Frame(arg: FormulaWff, res: Result)
def depth(f: FormulaWff): Int = step1(List(Frame(f, NotExpanded))) match {
case Frame(arg, Calculated(res)) :: Nil => res
}
#tailrec
def step1(stack: List[Frame]): List[Frame] = {
val x = step(stack, Nil)
x match {
case Frame(arg, Calculated(res)) :: Nil => x
case _ => step1(x)
}
}
#tailrec
def step(stack: List[Frame], acc: List[Frame]): List[Frame] = {
stack match {
case Frame(_, Calculated(res1)) :: Frame(_, Calculated(res2)) :: Frame(And(e1, e2), Expanded) :: frames =>
step(frames, Frame(And(e1, e2), Calculated(1 + math.max(res1, res2))) :: acc)
case Frame(_, Calculated(res1)) :: Frame(_, Calculated(res2)) :: Frame(Or(e1, e2), Expanded) :: frames =>
step(frames, Frame(Or(e1, e2), Calculated(1 + math.max(res1, res2))) :: acc)
case Frame(_, Calculated(res1)) :: Frame(_, Calculated(res2)) :: Frame(Implies(e1, e2), Expanded) :: frames =>
step(frames, Frame(Implies(e1, e2), Calculated(1 + math.max(res1, res2))) :: acc)
case Frame(_, Calculated(res1)) :: Frame(Not(e1), Expanded) :: frames =>
step(frames, Frame(Not(e1), Calculated(1 + res1)) :: acc)
case Frame(Var(s), _) :: frames =>
step(frames, Frame(Var(s), Calculated(0)) :: acc)
case Frame(Not(e1), NotExpanded) :: frames =>
step(frames, Frame(Not(e1), Expanded) :: Frame(e1, NotExpanded) :: acc)
case Frame(And(e1, e2), NotExpanded) :: frames =>
step(frames, Frame(And(e1, e2), Expanded) :: Frame(e1, NotExpanded) :: Frame(e2, NotExpanded) :: acc)
case Frame(Or(e1, e2), NotExpanded) :: frames =>
step(frames, Frame(Or(e1, e2), Expanded) :: Frame(e1, NotExpanded) :: Frame(e2, NotExpanded) :: acc)
case Frame(Implies(e1, e2), NotExpanded) :: frames =>
step(frames, Frame(Implies(e1, e2), Expanded) :: Frame(e1, NotExpanded) :: Frame(e2, NotExpanded) :: acc)
case Frame(arg, Expanded) :: frames => step(frames, Frame(arg, Expanded) :: acc)
case Frame(arg, Calculated(res)) :: frames => step(frames, Frame(arg, Calculated(res)) :: acc)
case Nil => acc.reverse
}
}
How to make tree mapping tail-recursive?
Related
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)
}
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))
}
I have simple hierarchy
class A
case class B extends A
case class C extends A
case class D extends A
And need function
def f(list: List[A]) : (List[B], List[C], List[D]) = ???
I can collect B, C, D in muttable lists but I want write it in fucntional style
Another variation
list.foldLeft((List.empty[B], List.empty[C],List.empty[D])) { case ((bs, cs, ds), a) =>
a match {
case x: B => (x :: bs, cs, ds)
case x: C => (bs, x :: cs, ds)
case x: D => (bs, cs, x :: ds)
}
}
What could be more functional than good old Foldable with couple of std library instances from scalaz buddy.
import scalaz.syntax.foldable._
import scalaz.std.tuple._
import scalaz.std.list._
def f(list: List[A]) = list foldMap {
case b: B => (List(b), Nil, Nil)
case c: C => (Nil, List(c), Nil)
case d: D => (Nil, Nil, List(d))
}
Note however that long lists are note quite good with appending elements, so a little bit more efficient implementation could be
import scalaz.syntax.foldable._
import scalaz.std.tuple._
import scalaz.std.vector._
import scalaz.std.list._
import scalaz.syntax.std.tuple._
def f(list: List[A]) = list foldMap {
case b: B => (Vector(b), Vector( ), Vector( ))
case c: C => (Vector( ), Vector(c), Vector( ))
case d: D => (Vector( ), Vector( ), Vector(d))
} mapElements (_.toList, _.toList, _.toList)
As for me it's quite optimal to use accumulator with lists in such case:
case class Cortage(bs: List[B], cs: List[C], ds: List[D]) {
def asCortage = (bs, cs, ds)
}
def f(list: List[A], acc: Cortage = Cortage(List(), List(), List())): (List[B], List[C], List[D]) =
list match {
case x :: t => f(t,
x match {
case x:B => acc.copy(bs = x :: acc.bs)
case x:C => acc.copy(cs = x :: acc.cs)
case x:D => acc.copy(ds = x :: acc.ds)
})
case Nil => acc.asCortage
}
Because I can not comment answers, I provide my solution which
preserves order and includes case for A.
def f(xs: List[A]): (List[B], List[C], List[D]) = {
#tailrec
def group(xs: List[A], bs: List[B], cs: List[C], ds: List[D]): (List[B], List[C], List[D]) = xs match {
case Nil => (bs.reverse, cs.reverse, ds.reverse)
case (b: B) :: t => group(t, b :: bs, cs, ds)
case (c: C) :: t => group(t, bs, c :: cs, ds)
case (d: D) :: t => group(t, bs, cs, d :: ds)
case _ :: t => group(t, bs, cs, ds)
}
group(xs, List(), List(), List())
}
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)
}
A direct cut and paste of the following algorithm:
def msort[T](less: (T, T) => Boolean)
(xs: List[T]): List[T] = {
def merge(xs: List[T], ys: List[T]): List[T] =
(xs, ys) match {
case (Nil, _) => ys
case (_, Nil) => xs
case (x :: xs1, y :: ys1) =>
if (less(x, y)) x :: merge(xs1, ys)
else y :: merge(xs, ys1)
}
val n = xs.length / 2
if (n == 0) xs
else {
val (ys, zs) = xs splitAt n
merge(msort(less)(ys), msort(less)(zs))
}
}
causes a StackOverflowError on 5000 long lists.
Is there any way to optimize this so that this doesn't occur?
It is doing this because it isn't tail-recursive. You can fix this by either using a non-strict collection, or by making it tail-recursive.
The latter solution goes like this:
def msort[T](less: (T, T) => Boolean)
(xs: List[T]): List[T] = {
def merge(xs: List[T], ys: List[T], acc: List[T]): List[T] =
(xs, ys) match {
case (Nil, _) => ys.reverse ::: acc
case (_, Nil) => xs.reverse ::: acc
case (x :: xs1, y :: ys1) =>
if (less(x, y)) merge(xs1, ys, x :: acc)
else merge(xs, ys1, y :: acc)
}
val n = xs.length / 2
if (n == 0) xs
else {
val (ys, zs) = xs splitAt n
merge(msort(less)(ys), msort(less)(zs), Nil).reverse
}
}
Using non-strictness involves either passing parameters by-name, or using non-strict collections such as Stream. The following code uses Stream just to prevent stack overflow, and List elsewhere:
def msort[T](less: (T, T) => Boolean)
(xs: List[T]): List[T] = {
def merge(left: List[T], right: List[T]): Stream[T] = (left, right) match {
case (x :: xs, y :: ys) if less(x, y) => Stream.cons(x, merge(xs, right))
case (x :: xs, y :: ys) => Stream.cons(y, merge(left, ys))
case _ => if (left.isEmpty) right.toStream else left.toStream
}
val n = xs.length / 2
if (n == 0) xs
else {
val (ys, zs) = xs splitAt n
merge(msort(less)(ys), msort(less)(zs)).toList
}
}
Just playing around with scala's TailCalls (trampolining support), which I suspect wasn't around when this question was originally posed. Here's a recursive immutable version of the merge in Rex's answer.
import scala.util.control.TailCalls._
def merge[T <% Ordered[T]](x:List[T],y:List[T]):List[T] = {
def build(s:List[T],a:List[T],b:List[T]):TailRec[List[T]] = {
if (a.isEmpty) {
done(b.reverse ::: s)
} else if (b.isEmpty) {
done(a.reverse ::: s)
} else if (a.head<b.head) {
tailcall(build(a.head::s,a.tail,b))
} else {
tailcall(build(b.head::s,a,b.tail))
}
}
build(List(),x,y).result.reverse
}
Runs just as fast as the mutable version on big List[Long]s on Scala 2.9.1 on 64bit OpenJDK (Debian/Squeeze amd64 on an i7).
Just in case Daniel's solutions didn't make it clear enough, the problem is that merge's recursion is as deep as the length of the list, and it's not tail-recursion so it can't be converted into iteration.
Scala can convert Daniel's tail-recursive merge solution into something approximately equivalent to this:
def merge(xs: List[T], ys: List[T]): List[T] = {
var acc:List[T] = Nil
var decx = xs
var decy = ys
while (!decx.isEmpty || !decy.isEmpty) {
(decx, decy) match {
case (Nil, _) => { acc = decy.reverse ::: acc ; decy = Nil }
case (_, Nil) => { acc = decx.reverse ::: acc ; decx = Nil }
case (x :: xs1, y :: ys1) =>
if (less(x, y)) { acc = x :: acc ; decx = xs1 }
else { acc = y :: acc ; decy = ys1 }
}
}
acc.reverse
}
but it keeps track of all the variables for you.
(A tail-recursive method is one where the method only calls itself to get a complete answer to pass back; it never calls itself and then does something with the result before passing it back. Also, tail-recursion can't be used if the method might be polymorphic, so it generally only works in objects or with classes marked final.)