I am looking to build an evaluation tree, for starters, for arithmetic expressions.
I have the following case classes defined:
abstract class Expr
case class Num(n: Integer) extends Expr
case class Plus(e1: Expr, e2: Expr) extends Expr
My parser, when it sees the expression 1 + 1 + 1 produces the following tree:
Plus(Plus(Num(1), Num(1)), Num(1))
I then have the following data type defined:
case class Tree[Expr](e: Expr, children: List[Tree[Expr]])
Here is a badly drawn evaluation tree:
Num(1) Num(1)
----------------------------
Plus(Num(1), Num(1)) Num(1)
---------------------------------------
Plus(Plus(Num(1),Num(1)), Num(1))
I want to build up a tree data structure representing that. So, the resulting output of evaluation would be:
Tree(
Plus(Plus(Num(1), Num(1)), Num(1)),
List(Tree(Plus(Num(1),Num(1),
List(Tree(Num(1), List()),
Tree(Num(1), List()))),
Tree(Num(1), List())))
I want to have a method eval:
def eval(e: Expr, t: Tree[Expr]): Tree[Expr] = (e, t) match {
// Do the matching on Num
case Num(n) ........ =>
case Plus(e1, e2) ...... =>
}
Is it the right way to represent this evaluation tree and if so, how can I go about creating such a nested tree data structure.
EDIT: Here is a method eval for addition only
def eval(e: Expr): Tree[Expr] = e match {
case Num(n) => Tree(Num(n), Nil)
case Plus(e1, e2) => Tree(Plus(e1, e2), List(eval(e1), eval(e2)))
}
You may have it like this:
def toTree(e: Expr): Tree[Expr] = e match {
case Plus(e1, e2) => Tree(e, List(eval(e1), eval(e2)))
case _ => Tree(e, List())
}
However, you'd better omit Tree as #puhlen suggests. The following method should be enough:
def children(e: Expr): List[Expr] = e match {
case Plus(e1, e2) => List(e1, e2)
case _ => List()
}
Just use it wherever you would use Tree.children
Related
I am trying to find a tail recursive fold function for a binary tree. Given the following definitions:
// From the book "Functional Programming in Scala", page 45
sealed trait Tree[+A]
case class Leaf[A](value: A) extends Tree[A]
case class Branch[A](left: Tree[A], right: Tree[A]) extends Tree[A]
Implementing a non tail recursive function is quite straightforward:
def fold[A, B](t: Tree[A])(map: A => B)(red: (B, B) => B): B =
t match {
case Leaf(v) => map(v)
case Branch(l, r) =>
red(fold(l)(map)(red), fold(r)(map)(red))
}
But now I am struggling to find a tail recursive fold function so that the annotation #annotation.tailrec can be used.
During my research I have found several examples where tail recursive functions on a tree can e.g. compute the sum of all leafs using an own stack which is then basically a List[Tree[Int]]. But as far as I understand in this case it only works for the additions because it is not important whether you first evaluate the left or the right hand side of the operator. But for a generalised fold it is quite relevant. To show my intension here are some example trees:
val leafs = Branch(Leaf(1), Leaf(2))
val left = Branch(Branch(Leaf(1), Leaf(2)), Leaf(3))
val right = Branch(Leaf(1), Branch(Leaf(2), Leaf(3)))
val bal = Branch(Branch(Leaf(1), Leaf(2)), Branch(Leaf(3), Leaf(4)))
val cmb = Branch(right, Branch(bal, Branch(leafs, left)))
val trees = List(leafs, left, right, bal, cmb)
Based on those trees I want to create a deep copy with the given fold method like:
val oldNewPairs =
trees.map(t => (t, fold(t)(Leaf(_): Tree[Int])(Branch(_, _))))
And then proof that the condition of equality holds for all created copies:
val conditionHolds = oldNewPairs.forall(p => {
if (p._1 == p._2) true
else {
println(s"Original:\n${p._1}\nNew:\n${p._2}")
false
}
})
println("Condition holds: " + conditionHolds)
Could someone give me some pointers, please?
You can find the code used in this question at ScalaFiddle: https://scalafiddle.io/sf/eSKJyp2/15
You could reach a tail recursive solution if you stop using the function call stack and start using a stack managed by your code and an accumulator:
def fold[A, B](t: Tree[A])(map: A => B)(red: (B, B) => B): B = {
case object BranchStub extends Tree[Nothing]
#tailrec
def foldImp(toVisit: List[Tree[A]], acc: Vector[B]): Vector[B] =
if(toVisit.isEmpty) acc
else {
toVisit.head match {
case Leaf(v) =>
val leafRes = map(v)
foldImp(
toVisit.tail,
acc :+ leafRes
)
case Branch(l, r) =>
foldImp(l :: r :: BranchStub :: toVisit.tail, acc)
case BranchStub =>
foldImp(toVisit.tail, acc.dropRight(2) ++ Vector(acc.takeRight(2).reduce(red)))
}
}
foldImp(t::Nil, Vector.empty).head
}
The idea is to accumulate values from left to right, keep track of the parenthood relation by the introduction of a stub node and reduce the result using your red function using the last two elements of the accumulator whenever a stub node is found in the exploration.
This solution could be optimized but it is already a tail recursive function implementation.
EDIT:
It can be slightly simplified by changing the accumulator data structure to a list seen as a stack:
def fold[A, B](t: Tree[A])(map: A => B)(red: (B, B) => B): B = {
case object BranchStub extends Tree[Nothing]
#tailrec
def foldImp(toVisit: List[Tree[A]], acc: List[B]): List[B] =
if(toVisit.isEmpty) acc
else {
toVisit.head match {
case Leaf(v) =>
foldImp(
toVisit.tail,
map(v)::acc
)
case Branch(l, r) =>
foldImp(r :: l :: BranchStub :: toVisit.tail, acc)
case BranchStub =>
foldImp(toVisit.tail, acc.take(2).reduce(red) :: acc.drop(2))
}
}
foldImp(t::Nil, Nil).head
}
An example from lift cookbook, the pattern matching is bit curious here.
serve("issues" / "by-state" prefix {
case "open" :: Nil XmlGet _ => <p>None open</p>
case "closed" :: Nil XmlGet _ => <p>None closed</p>
case "closed" :: Nil XmlDelete _ => <p>All deleted</p>
})
I don't understand what the XmlGet _ part is doing.
Could anyone explain a bit?
One of Scala's nice niche features is that many binary operations (e. g. f(x, y)) can be invoked from the infix position x f y. This applies to normal method calls:
case class InfixMethodCalls(x: Int) {
def wild(y: Int): Int = x + y
}
val infix = InfixMethodCalls(3)
infix wild 4
type constructors:
// A simple union type based on http://www.scalactic.org/
trait Or[A, B]
case class Good[A, B](value: A) extends Or[A, B]
case class Bad[A, B](value: B) extends Or[A, B]
def myMethod(x: Int Or String): Int
// This is the same as
def myMethod(x: Or[Int, String]): Int
and unapply / unapplySeq:
object InfixMagic {
def unapply(x: Any) = Option((List(x), x))
}
123 match {
case v :: Nil InfixMagic x => println(s"got v: $v and x: $x")
}
// is the same as
123 match {
case InfixMagic(v :: Nil, x) => println(s"got v: $v and x: $x")
}
So in the case of XmlGet this syntax here:
case "open" :: Nil XmlGet _ =>
is the same as:
case XmlGet("open" :: Nil, _) =>
And the _ is ignoring the Req parameter, which is the second part of the returned value from TestGet.unapply.
If you go through RuleHelper class of liftweb framework one will be able to make few assumptions.
XmlGet and XmlDelete extends TestGet trait with unapply method and Request argument. So this part basically means: check if it's XmlGet\XmlDelete method with any request.
How list is separated from second part? Good question. Suppose implicit listStringToSuper and listServeMagic used for this purpose.
https://github.com/lift/framework/blob/master/web/webkit/src/main/scala/net/liftweb/http/rest/RestHelper.scala
Assume the following data-structure.
sealed abstract class Formula {...}
//... some other case classes
sealed abstract class BinaryConnective(f0: Formula, f1: Formula) extends Formula {
def getf0 = f0
def getf1 = f1
}
object BinaryConnective {
def unapply(bc : BinaryConnective) = Some((bc.getf0, bc.getf1))
}
final case class Conjunction(f0: Formula, f1: Formula) extends BinaryConnective(f0,f1)
final case class Disjunction(f0: Formula, f1: Formula) extends BinaryConnective(f0,f1)
final case class Implication(f0: Formula, f1: Formula) extends BinaryConnective(f0,f1)
final case class Equivalence(f0: Formula, f1: Formula) extends BinaryConnective(f0,f1)
I now wrote a function that has a lot of pattern-matching:
The return-type of getCondition is Formula => Option[HashMap[Variable, Formula]]
formula match {
//.. irrelevant cases not shown
case Conjunction(f0, f1) => (g : Formula) => {
g match {
case conj # Conjunction(g0, g1) => {
getCondition(f0)(conj.f0) match {
case Some(map0) => {
getCondition(f1)(conj.f1) match {
case Some(map1) if map0.forall{case (key, value) => map1.get(key).map(_ == value).getOrElse(true)} => {
Some(map0 ++ map1)
}
case _ => None
}
}
case None => None
}
}
case _ => None
}
}
}
Now to my question.
1) Is there a nicer way to express this code? A lot of matches going on.
Edit 1: I could not think of a nice-looking way to use things like map, filter etc.., but it seems very compact with for-comprehensions. I've also noticed that conj # was not necessary at all, which also made it a little simpler.
case Conjunction(f0, f1) => (g: Formula) => g match {
case Conjunction(g0, g1) => for {
map0 <- getCondition(f0)(g0)
map1 <- getCondition(f1)(g1)
if map0.forall {case (key, value) => map1.get(key).map(_ == value).getOrElse(true)}
} yield map0 ++ map1
case _ => None
}
2) This is the match for Conjunction. I would have to repeat it for Disjunction, Implication and Equivalence. g has to be of the same class as formula. The only thing that would change is case conj # Conjunction(g0, g1). I would have to adjust it to case disj # Disjunction(g0, g1) if formula is a Disjunction etc...
Is there a way to do it combined for all cases?
Option should provide a lot of useful functions to simplify your code.
For example, when you write something like:
o match {
case Some(e) => Some(transform(e))
case _ => None
}
You could just call map: o.map(transform)
I also invite you to look at the filter function for the cases including a condition.
EDIT: great suggestion by #om-nom-nom: For comprehensions can also be used (they actually are sugar relying on map, flatMap, filter, etc):
for{
e <- o
} yield transform(e)
So I got something like this:
abstract class Term
case class App(f:Term,x:Term) extends Term
case class Var(s:String) extends Term
case class Amb(a:Term, b:Term) extends Term //ambiguity
And a Term may look like this:
App(Var(f),Amb(Var(x),Amb(Var(y),Var(z))))
So what I need is all variations that are indicated by the Amb class.
This is used to represent a ambiguous parse forest and I want to type check each possible variation and select the right one.
In this example I would need:
App(Var(f),Var(x))
App(Var(f),Var(y))
App(Var(f),Var(z))
Whats the best way to create these variations in scala?
Efficiency would be nice, but is not really requirement.
If possible I like to refrain from using reflection.
Scala provides pattern matching solve these kinds of problems. A solution would look like:
def matcher(term: Term): List[Term] = {
term match {
case Amb(a, b) => matcher(a) ++ matcher(b)
case App(a, b) => for { va <- matcher(a); vb <- matcher(b) } yield App(va, vb)
case v: Var => List(v)
}
}
You can do this pretty cleanly with a recursive function that traverses the tree and expands ambiguities:
sealed trait Term
case class App(f: Term, x: Term) extends Term
case class Var(s: String) extends Term
case class Amb(a: Term, b: Term) extends Term
def det(term: Term): Stream[Term] = term match {
case v: Var => Stream(v)
case App(f, x) => det(f).flatMap(detf => det(x).map(App(detf, _)))
case Amb(a, b) => det(a) ++ det(b)
}
Note that I'm using a sealed trait instead of an abstract class in order to take advantage of the compiler's ability to check exhaustivity.
It works as expected:
scala> val app = App(Var("f"), Amb(Var("x"), Amb(Var("y"), Var("z"))))
app: App = App(Var(f),Amb(Var(x),Amb(Var(y),Var(z))))
scala> det(app) foreach println
App(Var(f),Var(x))
App(Var(f),Var(y))
App(Var(f),Var(z))
If you can change the Term API, you could more or less equivalently add a def det: Stream[Term] method there.
Since my abstract syntax is fairly large (and I have multiple) and I tried my luck with Kiama.
So here is the version Travis Brown and Mark posted with Kiama.
Its not pretty, but I hope it works. Comments are welcome.
def disambiguateRule: Strategy = rule {
case Amb(a: Term, b: Term) =>
rewrite(disambiguateRule)(a).asInstanceOf[List[_]] ++
rewrite(disambiguateRule)(b).asInstanceOf[List[_]]
case x =>
val ch = getChildren(x)
if(ch.isEmpty) {
List(x)
}
else {
val chdis = ch.map({ rewrite(disambiguateRule)(_) }) // get all disambiguate children
//create all combinations of the disambiguated children
val p = combinations(chdis.asInstanceOf[List[List[AnyRef]]])
//use dup from Kiama to recreate the term with every combination
val xs = for { newchildren <- p } yield dup(x.asInstanceOf[Product], newchildren.toArray)
xs
}
}
def combinations(ll: List[List[AnyRef]]): List[List[AnyRef]] = ll match {
case Nil => Nil
case x :: Nil => x.map { List(_) }
case x :: xs => combinations(xs).flatMap({ ys => x.map({ xx => xx :: ys }) })
}
def getChildren(x: Any): List[Any] = {
val l = new ListBuffer[Any]()
all(queryf {
case a => l += a
})(x)
l.toList
}
I want to write a scala program simplifying this mathematical expression using distributivity rule:
a*b+a*c = a(b+c)
I quickly wrote the following code in order to solve this example:
object Test {
sealed abstract class Expr
case class Var(name: String) extends Expr
case class BinOp(operator: String, left: Expr, right: Expr) extends Expr
def main(args: Array[String]) {
val expr = BinOp("+", BinOp("*", Var("a"), Var("b")), BinOp("*", Var("a"), Var("c")))
println(simplify(expr)) //outputs "a(b + c)"
}
def simplify(expr: Expr) : String = expr match {
case BinOp("+", BinOp("*", Var(x), Var(a)), BinOp("*", Var(y), Var(b))) if (x == y) => "" + x + "*(" + a + " + " + b + ")"
case _ => "" //no matter for the test since I test the first case statically
}
}
Is there a better way to achieve this?
What is the best way to manage the order of operand without duplicating cases for each combination (would be ugly...)? Indeed, what about these expressions:
a*b+a*c = a(b+c)
a*b+c*a = a(b+c)
b*a+a*c = a(b+c)
b*a+c*a = a(b+c)
If Expr keeps commutative law, it must be
def simplify(expr: Expr) : String = expr match {
case expr # BinOp("+", BinOp("*", Var(x), Var(a)), BinOp("*", Var(y), Var(b))) => {
def another(that: String) = {
Seq((x, a), (a, x)) find (_._1 == that) map (_._2)
}
val byY = another(y).map(z => BinOp("+", Var(y), BinOp("*", Var(z), Var(b)))) // combine by y
val byB = another(b).map(z => BinOp("+", Var(b), BinOp("*", Var(z), Var(y)))) // combine by b
(byY orElse byB getOrElse expr).toString
}
case _ => "" //no matter for the test since I test the first case statically
}
byY and byB have the same structure. This is not the best, you maybe reuse some piece of code. :P