I wrote some events in FSM, and discovered something I can not explain when pattern matching. I thought the following was completely legal, that is that I can send this actor either a message which is a vector[A] or vector[B].
when(State) {
case Event(content: Vector[A], _) => {
println("matched A")
stay
}
case Event(content: Vector[B], _) => {
println("matched B")
stay
}
}
However,
if I send the actor a vector[B] message it leads to
java.lang.ClassCastException: B cannot be cast to A
So basically it tries to match the first event eventhough the next would match.
I tried to make an even simpler pattern match example;
object Pattern extends App {
val n = Vector(1,2,3)
val s = Vector("S", "S", "S")
n match{
case e:Vector[String] => println("matched string")
case v:Vector[Int] => println("matched int")
}
}
This is actually not legal;
Error:(8, 12) pattern type is incompatible with expected type;
found : Vector[String]
required: scala.collection.immutable.Vector[Int]
case e:Vector[String] => println("matched string")
However, I am allowed to run my code if I do the following cast;
object Pattern extends App {
val n = Vector(1,2,3).asInstanceOf[Vector[Any]]
val s = Vector("S", "S", "S")
n match{
case e:Vector[String] => println(n(0).getClass)
case v:Vector[Int] => println("matched int")
}
}
The thing I find strange then is that I apparently say that Any could match a String, but the print is java.lang.Integer. So should I think of it as I have an vector[Int] that I say is a Vector[Any], since Vector[Any] could be a Vector[String] it matches that pattern, and again since it really is a vector[Int] I mask as Vector[Any] the print is fine too.
Could someone explain these pattern matching observations?
and how should I set up the messages so my state can handle both messages of Vector[A] and Vector[B]?
Due to type erasure of jvm type information is lost at runtime this kind of pattern matching (pattern matching with higher kinded types) is not supported directly.
Here are the ways to get around this problem
Instead I recommend you to wrap the vector in another container.
sealed trait Vectors
case class VectorString(vs: Vector[String]) extends Vectors
case class VectorInt(vi: Vector[Int]) extends Vectors
def doStuff(v: Vectors) = v match {
case VectorString(vs) => //be sure that vs is Vector[String]
case VectorInt(vi) =>
}
Ways to pattern match generic types in Scala
Using TypeTag
import scala.reflect.runtime.universe._
def handle[A: TypeTag](a: A): Unit =
typeOf[A] match {
case t if t =:= typeOf[List[String]] =>
// list is a string list
val r = a.asInstanceOf[List[String]].map(_.length).sum
println("strings: " + r)
case t if t =:= typeOf[List[Int]] =>
// list is an int list
val r = a.asInstanceOf[List[Int]].sum
println("ints: " + r)
case _ => // ignore rest
}
val ints: List[Int] = Nil
handle(List("hello", "world")) // output: "strings: 10"
handle(List(1, 2, 3)) // output: "ints: 6"
handle(ints) // output: "ints: 0" it works!
Related
I would like to achieve something akin to the strategy pattern in scala without resorting to pattern matching with a long list of case statements. Here is roughly what I have in mind:
trait HandlerTrait {
def handlerA(...): Unit
def handlerB(...): Unit
}
SomeClass1 extends HandlerTrait {
override def handlerA(...) {...}
override def handlerB(...) {...}
}
SomeClass2 extends HandlerTrait {
override def handlerA(...) {...}
override def handlerB(...) {...}
}
object MyApp extends App {
// 1. define bindings for these implementations
val myBindings = Map(x -> someClass1, y -> someClass2)
// 2. Such that implementation of someMethod targeting handlerA implementations could look like this:
def someMethod(object: ObjectType): Unit = {
myBindings.get(object.x) match {
case Some(entry) => entry.handlerA(object)
case None => ()
}
}
}
A few more things:
I don't know how many SomeClassXXX I will have. I will add as needed
to provide customizations on how to handle A/B/C ...
Given a key, I want to dispatch to the correct class and execute the targeted handler.
Is there a better more concise way of achieving this in scala?
I think one way to reduce boilerplate is to use type system rather than inheritance. For instance, if your handler is of type T => Unit then any function that satisfies this type can be a handler, there is no need to officially declare HandlerTrait and even someMethod.
Whether to use a Map or cases to map from a key to a handler is up to you. Both can be extended to handle new cases.
Here is an example to sum up what I'm proposing:
val currentlyDefinedStrategies: PartialFunction[String, Unit] = {
case "1" => println(1)
case "2" => println(2)
}
val newStrategies: PartialFunction[String, Unit] = {
case "3" => println(3)
}
val defaultStrategy: PartialFunction[String, Unit] = {
case _ => println("default")
}
And usage:
scala> currentlyDefinedStrategies("1")
1
scala> currentlyDefinedStrategies("3")
scala.MatchError: 3 (of class java.lang.String) ...
scala> currentlyDefinedStrategies.orElse(newStrategies)("3")
3
scala> currentlyDefinedStrategies.orElse(newStrategies)("4")
scala.MatchError: 4 (of class java.lang.String)
scala> currentlyDefinedStrategies.orElse(newStrategies).orElse(defaultStrategy)("4")
default
You can achieve similar pattern with Map or using other FP techniques. The main point is to keep the most relevant code and get rid of boilerplate. Of course, HandlerTrait might be useful to you for structuring your code and thinking in terms of classes rather than functions, but the idea is the same.
See also: https://pavelfatin.com/design-patterns-in-scala/#strategy
The above example is a bit simplified and you actually want to pass parameters to handler (println in our case). Here is how:
val currentlyDefinedStrategies: Int => PartialFunction[String, Unit] = (x) => {
case "1" => println("1: " + x)
case "2" => println("2: " + x)
case _ => println("default: " + x)
}
You can fix the argument without choosing a strategy:
scala> val noStrategy = currentlyDefinedStrategies(1)
noStrategy: PartialFunction[String,Unit] = <function1>
... and provide strategy afterwards:
scala> noStrategy("1")
1: 1
Or apply the strategy right away:
scala> currentlyDefinedStrategies(1)("1")
1: 1
You can also decide on your strategy first and then pass an argument:
val currentlyDefinedStrategies: PartialFunction[String, Int => Unit] = {
case "1" => x => println("1: " + x)
case "2" => x => println("2: " + x)
case _ => x => println("default: " + x)
}
scala> val handlerWithChosenStrategy = currentlyDefinedStrategies("1")
handlerWithChosenStrategy: Int => Unit = $anonfun$1$$Lambda$1374/666224848#59a9f3eb
scala> handlerWithChosenStrategy(1)
1: 1
I think the point is that FP is so rich and flexible that strategy pattern is really not a thing. It's basically just some function type that suits your convenience like type Strategy[T, -A, +B] = PartialFunction[T, A => B]. Example:
scala> type Strategy[T, -A, +B] = PartialFunction[T, A => B]
defined type alias Strategy
val currentlyDefinedStrategies: Strategy[String, Int, Unit] = {
case "1" => x => println("1: " + x)
case "2" => x => println("2: " + x)
case _ => x => println("default: " + x)
}
currentlyDefinedStrategies: Strategy[String,Int,Unit] = <function1>
scala> currentlyDefinedStrategies("1")(1)
1: 1
A more advanced concept would be an Expression Problem (here) where you need to extend both the operations you can do on types as well as adding new types.
I am trying to use pattern matching to detect a generic type of my own custom type based on this answer.
The code provided by author works as expected:
import scala.reflect.runtime.{universe => ru}
def matchList[A: ru.TypeTag](list: List[A]) = list match {
case strlist: List[String #unchecked] if ru.typeOf[A] =:= ru.typeOf[String] => println("A list of strings!")
case intlist: List[Int #unchecked] if ru.typeOf[A] =:= ru.typeOf[Int] => println("A list of ints!")
}
matchList(List("a", "b", "c"))
matchList(List(1,2,3))
correctly displays:
A list of strings!
A list of ints!
Now based on this I am trying to apply same pattern to detect the generic type of my custom class Foo. The code below is copy-pased, except it uses Foo instead of List:
import scala.reflect.runtime.{universe => ru}
class Foo[T](val data: T)
def matchFoo[A: ru.TypeTag](foo: Foo[A]) = {
println("Is string = " + (ru.typeOf[A] =:= ru.typeOf[String]))
println("Is int = " + (ru.typeOf[A] =:= ru.typeOf[Int]))
foo match {
case fooStr: Foo[String #unchecked] if ru.typeOf[A] =:= ru.typeOf[String] => println("Found String")
case fooInt: Foo[Int #unchecked] if ru.typeOf[A] =:= ru.typeOf[Int] => println("Found Int")
}
}
matchFoo(new Foo[String]("str"))
println("------------")
matchFoo(new Foo[Int](123))
Only this time it outputs not what I was expecting:
Is string = true
Is int = false
Found String
------------
Is string = false
Is int = true
Found String // wth?
How can the second call matchFoo(new Foo[Int](123)) display Found String? As you can see I even explicitly printed out the match conditions, and they are fine.
The code online: http://goo.gl/b5Ta7h
EDIT:
I got it working by extracting match conditions into a variable:
def matchFoo[A: ru.TypeTag](foo: Foo[A]) = {
val isString: Boolean = ru.typeOf[A] =:= ru.typeOf[String]
val isInt: Boolean = ru.typeOf[A] =:= ru.typeOf[Int]
println("Is string = " + isString)
println("Is int = " + isInt)
foo match {
case fooStr: Foo[String #unchecked] if isString => println("Found String")
case fooInt: Foo[Int #unchecked] if isInt => println("Found Int")
}
}
Code online: http://goo.gl/mLxYY2
But in my opinion the original version should also work. I don't think I'm missing operator precedence here, since wrapping conditions into parenthesis also doesn't help.
Is it a bug in Scala? I'm using Scala SDK v. 2.11.5 and JDK v. 1.8.0_25. The online CodingGround uses Scala SDK v. 2.10.3.
EDIT 2:
I've opened an issue in Scala's bugtracker for this. You can vote for it here.
This looks very much like a bug in the compiler which does not resolve the correct implicit (could be the presence of the #unchecked?).
case fooStr: Foo[String #unchecked] if ru.typeOf[A] =:= ru.typeOf[String] =>
println(implicitly[TypeTag[String]]) // will print TypeTag[Int]
By looking at the byte code, the compiler uses the TypeTag passed to the method ($evidence).
A (limited) workaround could be to use ru.definitions.IntTpe:
case fooStr: Foo[Int #unchecked] if ru.typeOf[A] =:= ru.definitions.IntTpe =>
println("That's an Int")
I know a lot of questions exist about type erasure and pattern matching on generic types, but I could not understand what should I do in my case from answers to those, and I could not explain it better in title.
Following code pieces are simplified to present my case.
So I have a trait
trait Feature[T] {
value T
def sub(other: Feature[T]): Double
}
// implicits for int,float,double etc to Feature with sub mapped to - function
...
Then I have a class
class Data(val features: IndexedSeq[Feature[_]]) {
def sub(other: Data): IndexedSeq[Double] = {
features.zip(other.features).map {
case(e1: Feature[t], e2: Feature[y]) => e1 sub e2.asInstanceOf[Feature[t]]
}
}
}
And I have a test case like this
case class TestFeature(val value: String) extends Feature[String] {
def sub(other: Feature[String]): Double = value.length - other.length
}
val testData1 = new Data(IndexedSeq(8, 8.3f, 8.232d, TestFeature("abcd"))
val testData2 = new Data(IndexedSeq(10, 10.1f, 10.123d, TestFeature("efg"))
testData1.sub(testData2).zipWithIndex.foreach {
case (res, 0) => res should be (8 - 10)
case (res, 1) => res should be (8.3f - 10.1f)
case (res, 2) => res should be (8.232d - 10.123d)
case (res, 3) => res should be (1)
}
This somehow works. If I try sub operation with instances of Data that have different types in same index of features, I get a ClassCastException. This actually satisfies my requirements, but if possible I would like to use Option instead of throwing an exception. How can I make following code work?
class Data(val features: IndexedSeq[Feature[_]]) {
def sub(other: Data): IndexedSeq[Double] = {
features.zip(other.features).map {
// of course this does not work, just to give idea
case(e1: Feature[t], e2: Feature[y]) if t == y => e1 sub e2.asInstanceOf[Feature[t]]
}
}
}
Also I am really inexperienced in Scala, so I would like to get feedback on this type of structure. Are there another ways to do this and which way would make most sense?
Generics don't exist at runtime, and an IndexedSeq[Feature[_]] has forgotten what the type parameter is even at compile time (#Jatin's answer won't allow you to construct a Data with a list of mixed types of Feature[_]). The easiest answer might be just to catch the exception (using catching and opt from scala.util.control.Exception). But, to answer the question as written:
You could check the classes at runtime:
case (e1: Feature[t], e2: Feature[y]) if e1.value.getClass ==
e2.value.getClass => ...
Or include the type information in the Feature:
trait Feature[T] {
val value: T
val valueType: ClassTag[T] // write classOf[T] in subclasses
def maybeSub(other: Feature[_]) = other.value match {
case valueType(v) => Some(actual subtraction)
case _ => None
}
}
The more complex "proper" solution is probably to use Shapeless HList to preserve the type information in your lists:
// note the type includes the type of all the elements
val l1: Feature[Int] :: Feature[String] :: HNil = f1 :: f2 :: HNil
val l2 = ...
// a 2-argument function that's defined for particular types
// this can be applied to `Feature[T], Feature[T]` for any `T`
object subtract extends Poly2 {
implicit def caseFeatureT[T] =
at[Feature[T], Feature[T]]{_ sub _}
}
// apply our function to the given HLists, getting a HList
// you would probably inline this
// could follow up with .toList[Double]
// since the resulting HList is going to be only Doubles
def subAll[L1 <: HList, L2 <: HList](l1: L1, l2: L2)(
implicit zw: ZipWith[L1, L2, subtract.type]) =
l1.zipWith(l2)(subtract)
That way subAll can only be called for l1 and l2 all of whose elements match, and this is enforced at compile time. (If you really want to do Options you can have two ats in the subtract, one for same-typed Feature[T]s and one for different-typed Feature[_]s, but ruling it out entirely seems like a better solution)
You could do something like this:
class Data[T: TypeTag](val features: IndexedSeq[Feature[T]]) {
val t = implicitly[TypeTag[T]]
def sub[E: TypeTag](other: Data[E]): IndexedSeq[Double] = {
val e = implicitly[TypeTag[E]]
features.zip(other.features).flatMap{
case(e1, e2: Feature[y]) if e.tpe == t.tpe => Some(e1 sub e2.asInstanceOf[Feature[T]])
case _ => None
}
}
}
And then:
case class IntFeature(val value: Int) extends Feature[Int] {
def sub(other: Feature[Int]): Double = value - other.value
}
val testData3 = new Data(IndexedSeq(TestFeature("abcd")))
val testData4 = new Data(IndexedSeq(IntFeature(1)))
println(testData3.sub(testData4).zipWithIndex)
gives Vector()
The context of my question is similar to some others asked in the forum, but I cannot find an exact match and it still remains a mystery to me after viewing those answers. So I appreciate it if someone can help. The context of my question is to match a singleton class object using a pattern match.
For example, if I am implementing a list structure of my own, like this
// An implementation of list
trait AList[+T] // covariant
case class Cons[+T](val head: T, val tail: AList[T]) extends AList[T]
case object Empty extends AList[Nothing] // singleton object
// an instance of implemented list
val xs = Cons(1, Cons(2, Cons(3, Empty)))
// pattern matching in a method - IT WORKS!
def foo[T](xs: AList[T]) = xs match {
case Empty => "empty"
case Cons(x, xss) => s"[$x...]"
}
println(foo(xs)) // => [1...]
// pattern matching outside - IT RAISES ERROR:
// pattern type is incompatible with expected type;
// found : Empty.type
// required: Cons[Nothing]
val r: String = xs match {
case Empty => "EMPTY"
case Cons(x, xss) => s"[$x...]"
}
println(r) // does NOT compile
To me they look like the same "matching" on the same "objects", how come one worked and the other failed? I guess the error had something to do with the different of matching expr in and out of methods, but the message given by the compiler was quite misleading. Does it mean we need to explicitly cast xs like xs.asInstanceOf[AList[Int]] when "matching" outside?
Compiler tells you that type of xs is Cons and it can't be Empty, so your first case is pointless.
Try this:
val r: String = (xs: AList[Int]) match {
case Empty => "EMPTY"
case Cons(x, xss) => s"[$x...]"
}
Or this:
val ys: AList[Int] = xs
val r: String = ys match {
case Empty => "EMPTY"
case Cons(x, xss) => s"[$x...]"
}
In this case compiler don't knows that case Empty is pointless.
It's exactly what you are doing with def foo[T](xs: AList[T]) = .... You'd get the same compilation error with def foo[T](xs: Cons[T]) = ....
In this particular example valid and exhaustive match looks like this:
val r: String = xs match {
// case Empty => "EMPTY" // would never happened.
case Cons(x, xss) => s"[$x...]"
}
Addition: you should make your AList trait sealed:
sealed trait AList[+T]
It allows compiler to warn you on not exhaustive matches:
val r: String = (xs: AList[Int]) match {
case Cons(x, xss) => s"[$x...]"
}
<console>:25: warning: match may not be exhaustive.
It would fail on the following input: Empty
val r: String = (xs: AList[Int]) match {
^
The parameter of foo is a AList[T], so in the first case the matching is being done on a AList[T]. In the second case the matching is being done on a Cons[+T].
Basically matching is done on a object type, not on a object.
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
}