Alternative pattern matching with variable binding? - scala

I try to implement an equivalence relation over terms which I also would like to match against some patterns. However my relation is symmetric and therefore, the pattern matching must reflect this too.
Have a look at the following example:
abstract class Term
case class Constructor(txt:String) extends Term
case class Variable(txt:String) extends Term
case class Equality(t1:Term, t2:Term)
def foobar(e:Equality) = e match {
case Equality(Variable(x),Constructor(y)) => "do something rather complicated with x and y"
case Equality(Constructor(y),Variable(x)) => "do it all over again"
}
Infact I would like to do something like this
def foobar(e:Equality) = e match {
case Equality(Variable(x),Constructor(y)) | Equality(Constructor(y),Variable(x))
=> "yeah! this time we need to write the code only one time ;-)"
}
However, as noted e.g. in here, this is not allowed. Does someone have a nice solution for this kind of problem? Any help/pointer is highly appreciated.

You could create your own unapply method like this:
object CVEquality {
def unapply(e: Equality): Option(String, String) = e match {
case Equality(Variable(v), Constructor(c)) => Some(c -> v)
case Equality(Constructor(c), Variable(v)) => Some(c -> v)
case _ => None
}
}
Usage:
def foobar(e:Equality) = e match {
case CVEquality(c, v) => "do something rather complicated with c and v"
}
The easiest way is to create method for something rather complicated:
def complicated(c: String, v: String) = "do something rather complicated with c and v"
def foobar(e:Equality) = e match {
case Equality(Variable(x),Constructor(y)) => complicated(y, x)
case Equality(Constructor(y),Variable(x)) => complicated(y, x)
}

Related

Can I avoid using asInstanceOf in a pattern match when matching a stateful subclass object?

As I was modelling expressions like Var("x") or Number(7) and writing an eval function with pattern matching, I ran into a case where I could not avoid using the ´asInstanceOf` method.
2 restrictions
I do not want to avoid pattern matching by declaring an eval method in Expr and define it in its subclasses (cf. Expression problem, I prefer pattern match).
I also do not want something like Var("x", 7).
sealed trait Expr
object Expr {
def eval(e: Expr): Int = e match {
case Number(n) => n
case Var(_) => e.asInstanceOf[Var].getValue()
}
}
case class Number(n: Int) extends Expr
case class Var(s: String) extends Expr {
var value = 0
def getValue(): Int = value
def updateValue(x: Int): Unit = {
this.value = x
}
}
val x = Var("x")
x.updateValue(1)
Expr.eval(x) // 1
When I define the second case like this: case Var(x) => Var(x).getValue(), i get Expr.eval(x) // 0. This is, because Var(x) on the right side will construct a fresh Var with value 0.
I'm ok with using asInstanceOf but in the sense of improvement, I wonder if there is a cleaner solution than using asInstanceOf, which I haven't found yet.
You can use # to bind a variable to a pattern. Use it like this:
def eval(e: Expr): Int = e match {
case Number(n) => n
case v#Var(_) => v.getValue()
}
You can also check the type of a variable in a pattern match
def eval(e: Expr): Int = e match {
case Number(n) => n
case v: Var => v.getValue()
}

Scala : Pattern matching with Option[Foo] and parameter of Foo

How can rewrite the following to make it more 'Scala way' or use just one match?
case class Foo(bar: Any)
val fooOpt = Some(Foo("bar as String"))
def isValid(p: Any) = p match {
case _ # (_: String | _: Int) => true
case _ => false
}
//Is it possible to check for the type of bar directly in this if statement?
fooOpt match {
case Some(f) if isValid(f.bar) => doSomething
case _ => doSomethingElse
}
One alternative would be using the isInstanceOf.
fooOpt match {
case Some(f) if f.bar.isInstanceOf[String] => doSomething
case Some(f) if f.bar.isInstanceOf[Int] => doSomething //could also rewrite to use just one case
case _ => doSomethingElse
}
Is there other way?
This can all be done in one big pattern match:
fooOpt match {
case Some(Foo(_: Int | _: String)) => doSomething
case _ => doSomethingElse
}
If you want to get the Int or String out, just split that case:
fooOpt match {
case Some(Foo(i: Int)) => doSomething
case Some(Foo(s: String)) => doSomething
case _ => doSomethingElse
}
Is there other way?
Although the solution with one big patten match works(and can be used if you really can't change bar to anything more specific than Any), it is not a proper 'Scala way' of dealing with this situations in general if you have control over Foo.
A better way would be to make Foo generic:
case class Foo[T](bar: T)
And have either a generic doSomething, if it can work with any particular T:
def doSomething[T](foo: Foo[T]): SomeType = ???
or to have different versions of it for different possible T's you have, if it should react on them differently:
def doSomethingWithString(foo: Foo[String]): SomeType = ???
def doSomethingWithInt(foo: Foo[Int]): SomeType = ???
Then you can use it just like this:
val fooOpt = Some(Foo("bar as String"))
fooOpt.map(doSomething).orElse(doSomethingElse)
or like this:
val fooOptString = Some(Foo("bar as String"))
fooOptString.map(doSomethingWithString).orElse(doSomethingElse)
val fooOptInt = Some(Foo(1))
fooOptInt.map(doSomethingWithInt).orElse(doSomethingElse)
So, in this case compiler checks types for you, answering to:
Is it possible to check for the type of bar directly?
And in many situations you can avoid using pattern match at all, using methods like map, orElse, etc. with proper typing. This might be an answer for this:
could also rewrite to use just one case

Improving Pattern-matching Code

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)

Building variations of nested case classes

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
}

Match "fallthrough": executing same piece of code for more than one case?

What is the Scala's way to write the following code:
int i;
switch(i) {
case 1:
a();
break;
case 2:
case 15:
b();
c();
break;
default: foo()
}
I.e. what is the idiomatic way of executing the same piece of code based on multiple case values?
i match {
case 1 => a
case 2 =>
case 15 => { b
c }
case _ => foo
}
Doesn't quite seem do the trick, since Scala evaluates the match value based on the first matching case, i.e. if i=2 the code will return nothing.
Thanks for help!
According to this conversation there is no fallthrough, but you can make use of |.
This should do the trick:
i match {
case 1 => a
case 2 | 15 => b
c
case _ => foo
}
Case statements can actually include additional logic guards using a standard if statement. So you could do something like:
i match {
case x if x == 1 => a
case x if (x == 2 | x == 15) => b; c;
case _ => foo
}
The matching guards can be any boolean function or composition of functions, so it gives it a lot more power than the standard switch statement in Java.
While not applicable here, for more complex problems you can 'fallthrough' in a sense using the andThen function on partial functions.
def do_function_a() { println("a"); }
def do_function_b() { println("b"); }
val run_function:PartialFunction[String, String] = {
case "a" => do_function_a(); "b"
case "b" => do_function_b(); "c"
}
(run_function andThen run_function)("a") // a\nb
If you are dealing with actual classes (instead of strings or ints), you need _: before each class to make them into a pattern before joining them with |.
sealed trait ShipCondition
case class ShipOnFire() extends ShipCondition
case class FoodSucks() extends ShipCondition
case class MateySnoresTooLoud() extends ShipCondition
case class Ok() extends ShipCondition
val condition = ShipOnFire()
def checkCondition(cond: ShipCondition): Unit = {
cond match {
case c # (_: ShipOnFire | _: FoodSucks) => println("Abandon Ship!") // can also use `c` for something. It has the type ShipCondition
case (_: MateySnoresTooLoud | _: Ok) => println("Deal with it!")
}
}
checkCondition(condition) // Abandon Ship!
You get nice exhaustive checking too! Note that you cannot do case class destructuring when using alternative pattern matching (e.g. case (MateySnoresTooLoud(str) | _: Ok) => will fail to compile.