Assign value to variable in Scala Parser - scala

i have a question about the Parser in Scala. I'll just post the important part here so that there would not be too much codes. For the eval Function:
def eval(t: Term): Double = t match {
case Addition(l, r) => eval(l) + eval(r)
case Multiplication(l, r) => eval(l) * eval(r)
case Numeric(i) => i
case Variable("X") => 3
}
And the calculate function:
def calculate(arg: String): Double = {
return eval(parseAll(term, arg).get)
}
now i should overload the function "calculate" so that it takes an extra Parameter tup : (String, Double) and assign the value for this String. For example ("Y",2) then Y = 2 in the Parser. And then calculate the parser. But i don't know how to assign the value for this String. I had a stupid idea and tried this but it didn't work.
def calculate(arg: String, tup : (String, Double)) : Double = {
tup match {
case (a,b) => {
def eval(t : Term): Double = t match {
case Variable(a) => b
}
return eval(parseAll(term, arg).get)
}
}
can you guys pls help me out ? Thank you !!

You're almost there, you just need to tell the compiler that the a in your Variable pattern is actually the a from your (a, b) pattern. By default, what you do is called shadowing of the variable name a (in the scope of this pattern match, a is the value extracted in Variable, and the other a is forgotten).
What you want is something like
...
case Variable(`a`) => b
...
or, if your expression gets a little more complicated, you should rather use a guard:
...
case Variable(v) if v == a => b
...
EDIT However, now your eval function is not well defined. You need to put it all at once:
def eval(t: Term, varAssignement: (String, Double)): Double = t match {
case Addition(l, r) => eval(l) + eval(r)
case Multiplication(l, r) => eval(l) * eval(r)
case Numeric(i) => i
case Variable(a) if a == varAssignment._1 => varAssignment._2
}
Or, if you want to have multiple variables:
def eval(t: Term, assignments: Map[String, Double]): Double = t match {
case Addition(l, r) => eval(l) + eval(r)
case Multiplication(l, r) => eval(l) * eval(r)
case Numeric(i) => i
case Variable(a) if assignments.exists(a) => assignments(a)
}
Beware that you'll still get MatchErrors whenever an unassigned variable is used.

Related

Scala - standard recursive pattern match on list

Given:
def readLines(x: String): List[String] = Source.fromFile(x).getLines.toList
def toKVMap(fName : String): Map[String,String] =
readLines(fName).map(x => x.split(',')).map { case Array(x, y) => (x, y) }.toMap
I want to be able to take a string and a list of files of replacements and replace bracketed items. So if I have:
replLines("Hello",["cat"]) and cat contains ello,i!, I want to get back Hi!
I tried:
def replLines(inpQ : String, y : List[String]): String = y match {
case Nil => inpQ
case x::xs => replLines(toKVMap(x).fold(inpQ) {
case ((str: String), ((k: String), (v: String))) =>
str.replace("[" + k + "]", v).toString
}, xs)
}
I think the syntax is close, but not quite there. What have I done wrong?
What you're looking for is most likely this (note the foldLeft[String] instead of fold:
def replLines(inpQ: String, y: List[String]): String = y match {
case Nil => inpQ
case x :: xs => replLines(toKVMap(x).foldLeft[String](inpQ) {
case ((str: String), ((k: String), (v: String))) =>
str.replace("[" + k + "]", v)
}, xs)
}
fold generalizes the fold initial argument too much, and considers it a Serializable, not a String. foldLeft (and foldRight, if you prefer to start your replacements from the end) allows you to explicitly specify the type you fold on
EDIT: In fact, you don't even need a recursive pattern matching at all, as you can map your replacements directly to the list:
def replLines2(inpQ: String, y: List[String]): String =
y.flatMap(toKVMap).foldLeft[String](inpQ) {
case (str, (k, v)) => str.replace(s"[$k]", v)
}

Pattern Matching Against Anonymous

I'm trying to do something like:
private val isOne = (x: Int) => x == 1
private val isTwo = (x: int) => x == 2
def main(x: Int): String = {
x match {
case isOne => "it's one!"
case isTwo => "it's two!"
case _ => ":( It's not one or two"
}
}
Unfortunately... doesn't look like my syntax is right or maybe that's just no possible in Scala... any suggestions?
This isn't going to work for two reasons. First,
case isOne => ...
is not what you think it is. isOne within the match is just a symbol that will eagerly match anything, and not a reference to the val isOne. You can fix this by using backticks.
case `isOne` => ...
But this still won't do what you think it does. x is an Int, and isOne is a Int => Boolean, which means they will never match. You can sort of fix it like this:
def main(x: Int): String = {
x match {
case x if(isOne(x)) => "it's one!"
case x if(isTwo(x)) => "it's two!"
case _ => ":( It's not one or two"
}
}
But this isn't very useful, and case 1 => .... does the job just fine.

Scala matching, resolving the same variable from two different patterns

Say I have the following
case class IntWrap(value:Int)
I would like to extract the same variable from two cases as follows:
x match {
case value:Int | IntWrap(value) => dosomethingwith(x)
case _ => ???
}
but the only way I have been able to do this is as:
x match {
case value:Int => dosomethingwith(x)
case IntWrap(value) => dosomethingwith(x)
case _ => ???
}
Is there a better way, as in my real life case dosomething is actually a large block of code which is not so easy to encapsulate.
If it is really the case that you want to do something with x, not with the extracted value, then the following would work:
case class IntWrap(value:Int) // extends T
def dosomethingwith(x: Any) = x
val x: Any = IntWrap(101)
x match {
case _: Int | _: IntWrap => dosomethingwith(x)
case _ => ???
}
If you actually want to work with the extracted value, you could factor out the corresponding match block into its own extractor and reuse that wherever necessary:
x match {
case Unwrap(value) => dosomethingwith(value)
case _ => ???
}
object Unwrap {
def unapply(x: Any) = x match {
case x: Int => Some((x))
case IntWrap(value) => Some((value))
case _ => None
}
}
I honestly don't see an issue with the way you are doing things. As long as dosomethingwith is a separate function then I don't see any issues with duplicate code. If your code looked like this then I don't see any need to come up with other solutions:
def foo(x:Any){
x match {
case value:Int => dosomethingwith(value)
case IntWrap(value) => dosomethingwith(value)
case _ => ???
}
}
def dosomethingwith(x:Int){
//do something complicated here...
}
I came up with sth a little bit different, but it may help you avoid duplicates:
case class IntWrap(value: Int)
implicit def intWrapToInt(intWrap: IntWrap) = intWrap.value
def matchInt(x: AnyVal) = x match {
case i: Int => println("int or intWrap")
case _ => println("other")
}
//test
matchInt(IntWrap(12)) //prints int or intWrap
matchInt(12) //prints int or intWrap
matchInt("abc") //prints other
It won't work for every reference, though. So, be careful.

How do you determine the type of the catch all in a scala pattern match case?

If you have a pattern matching (case) in Scala, for example:
foo match {
case a: String => doSomething(a)
case f: Float => doSomethingElse(f)
case _ => ? // How does one determine what this was?
}
Is there a way to determine what type was actually caught in the catch-all?
case x => println(x.getClass)
Too easy :-)
Basically, you just need to bind the value in your catch-all statement to a name (x in this case), then you can use the standard getClass method to determine the type.
If you're trying to perform specific logic based on the type, you're probably doing it wrong. You could compose your match statements as partial functions if you need some 'default' cases that you don't want to define inline there. For instance:
scala> val defaultHandler: PartialFunction[Any, Unit] = {
| case x: String => println("String: " + x)
| }
defaultHandler: PartialFunction[Any,Unit] = <function1>
scala> val customHandler: PartialFunction[Any, Unit] = {
| case x: Int => println("Int: " + x)
| }
customHandler: PartialFunction[Any,Unit] = <function1>
scala> (customHandler orElse defaultHandler)("hey there")
String: hey there
foo match {
case a: String => doSomething(a)
case f: Float => doSomethingElse(f)
case x => println(x.getClass)
}

Simplify expression in Scala

I have such case classes:
abstract class Tree
case class Sum(l: Tree, r: Tree) extends Tree
case class Var(n: String) extends Tree
case class Const(v: Int) extends Tree
Now i write such object :
object Main {
type Environment = String => Int
def derive(t: Tree, v: String): Tree = t match {
case Sum(l, r) => Sum(derive(l, v), derive(r, v))
case Var(n) if (v == n) => Const(1)
case _ => Const(0)
}
def eval(t: Tree, env: Environment): Int = t match {
case Sum(l, r) => eval(l, env) + eval(r, env)
case Var(n) => env(n)
case Const(v) => v
}
def simple(t: Tree): Const = t match {
case Sum(l, r) if (l.isInstanceOf[Const] && r.isInstanceOf[Const]) => Const(l.asInstanceOf[Const].v + r.asInstanceOf[Const].v)
case Sum(l, r) if (l.isInstanceOf[Sum] && r.isInstanceOf[Sum]) => Const(simple(l).v+ simple(r).v)
case Sum(l, r) if (l.isInstanceOf[Sum]) => Const(simple(l).v + r.asInstanceOf[Const].v)
case Sum(l, r) if (r.isInstanceOf[Sum]) => Const(simple(r).v + l.asInstanceOf[Const].v)
}
def main(args: Array[String]) {
val exp: Tree = Sum(Sum(Var("x"), Var("x")), Sum(Const(7), Var("y")))
val env: Environment = {
case "x" => 5
case "y" => 7
}
println("Expression: " + exp)
println("Evaluation with x=5, y=7: " + eval(exp, env))
println("Derivative relative to x:\n " + derive(exp, "x"))
println("Derivative relative to y:\n " + derive(exp, "y"))
println("Simplified expression:\n" + simple(derive(exp, "x")))
}
}
I am new in scala. Is it possible write method simple with small count of code and maybe in scala way?
Thanks for advice.
You're almost there. In Scala, extractors can be nested:
def simple(t: Tree): Const = t match {
case Sum(Const(v1), Const(v2)) => Const(v1 + v2)
case Sum(s1 # Sum(_,_), s2 # Sum(_, _)) => Const(simple(s1).v+ simple(s2).v)
case Sum(s # Sum(_, _), Const(v)) => Const(simple(s).v + v)
case Sum(Const(v), s # Sum(_, _)) => Const(simple(s).v + v)
}
Of course, this will give you some warnings about incomplete matches, and the sx # Sum(_, _) repeatedly suggests that there may be a better approach that includes matching on Const and Var at the root level and making more recursive calls to simple.
Although this question has been closed, but I think this version should be a better one,
def simplify(t: Tree): Tree = t match {
case Sum(Const(v1), Const(v2)) => Const(v1 + v2)
case Sum(Const(v1), Sum(Const(v2), rr)) => simplify(Sum(Const(v1 + v2), simplify(rr)))
case Sum(l, Const(v)) => simplify(Sum(Const(v), simplify(l)))
case Sum(l, Sum(Const(v), rr)) => simplify(Sum(Const(v), simplify(Sum(l, rr))))
case Sum(Sum(ll, lr), r) => simplify(Sum(ll, simplify(Sum(lr, r))))
case Sum(Var(n), r) => Sum(simplify(r), Var(n))
case _ => t
}
it seems works with "complex" expressions with variables.
Just a small improvement:
def derive(t: Tree, v: String): Tree = t match {
case Sum(l, r) => Sum(derive(l, v), derive(r, v))
case Var(`v`) => Const(1)
case _ => Const(0)
}
How about this:
def simplify(t: Tree): Tree = t match {
case Sum(Const(v1),Const(v2)) => Const(v1+v2)
case Sum(left,right) => simplify(Sum(simplify(left),simplify(right)))
case _ => t //Not necessary, but for completeness
}
Note that it returns a Tree, not a Const, so it should be able to simplify trees with variables too.
I'm learning Scala so any suggestions as to why this wouldn't work etc. are more than welcome :-)
EDIT: Just discovered that the second case causes an infinite loop when using variables. Substitute it with:
case Sum(left,right) => Sum(simplify(left),simplify(right))
Unfortunately this breaks when left and right return Const, which could be simplified even further (e.g. Sum(Const(2),Const(3))).