Given the following method,
scala> def f(x: Option[String]): Either[String, Int] = x match {
case Some(x) => try { Right(x.toInt) }
catch {
case _: NumberFormatException => Left(s"Not an int: $x")
}
case None => Left("No String present.")
}
f: (x: Option[String])Either[String,Int]
testing
scala> f(None)
res0: Either[String,Int] = Left(No String present.)
scala> f(Some("44"))
res2: Either[String,Int] = Right(44)
scala> f(Some("zipp"))
res3: Either[String,Int] = Left(Not an int: zipp)
How would a Monad transformer be used here?
Note - I don't know if it's a good example since it's so short (and the pattern match might be the cleanest way), but I'm curious anyway.
Related
In scala, a pattern matching for a class has to be conducted in the following way:
val clz: Class[_] = ???
clz match {
case v if clz == classOf[String] =>
// do something
case v if clz == classOf[Int] =>
// do something
//...
}
The boilerplate code v if clz == is really redundant and I'd like to have them removed or reduced, since functions like classOf[String] and classOf[int] can be inlined and used like constant. So how can I do this?
There is some support, mostly in relation to array element types:
scala> import reflect.ClassTag
import reflect.ClassTag
scala> val c: Class[_] = classOf[Int]
c: Class[_] = int
scala> (ClassTag(c): Any) match { case ClassTag.Boolean => "bool" case ClassTag.Int => "int" }
res0: String = int
but the use case is to simplify type tests
scala> def f[A: ClassTag] = ("abc": Any) match { case _: A => "A" case _ => "other" }
f: [A](implicit evidence$1: scala.reflect.ClassTag[A])String
scala> f[Int]
res1: String = other
scala> f[String]
res2: String = A
Maybe one argument for classTag not looking like a stable id is that classOf[C] evaluated in different classloaders don't compare equal.
Suppose I have a function to check a string:
case class MyError(msg: String)
val oops = MyError("oops")
def validate(s: String):Either[MyError, Unit] =
if (s == "a") Right(()) else Left(oops)
Now I would like to reuse it and write a new function to check the head of a list of strings and return either an error or the list tail.
// should be validateHeadOfList but I don't want to change the name now
def validateList(xs: List[String]): Either[MyError, List[String]] =
xs match {
case head::tail =>
validate(head).fold(err => Left(err), _ => Right(tail))
case _ => Left(oops)
}
This function works but doesn't look elegant. How would you improve it ?
Your implementation looks rather idiomatic to me, but if you're looking for a possibly more concise alternative - I think this does exactly the same, and is (arguably) more concise:
def validateList(xs: List[String]): Either[MyError, List[String]] =
xs.headOption.map(validate).map(_.right.map(_ => xs.tail)).getOrElse(Left(oops))
Assuming you actually want to return either a single error or the original list, then the following will work. I can't comment on whether this is idiomatic Scala though.
case class MyError(msg: String)
val oops = MyError("oops")
def validate(s: String): Either[MyError, Unit] =
if (s == "a") ().asRight else oops.asLeft
final def validateList(list: List[String]): Either[MyError, List[String]] = {
#scala.annotation.tailrec
def loop(xs: List[String]): Either[MyError, List[String]] = {
xs match {
case head :: tail =>
validate(head) match {
case Left(error) => error.asLeft
case _ => loop(tail)
}
case _ => list.asRight
}
}
loop(list)
}
For example:
scala> validateList(List("a", "a", "a"))
res0: Either[MyError,List[String]] = Right(List(a, a, a))
scala> validateList(List("a", "b", "a"))
res1: Either[MyError,List[String]] = Left(MyError(oops))
I am getting very bizarre behavior (at least it seems to me) with the orElse method defined on PartialFunction
It would seem to me that:
val a = PartialFunction[String, Unit] {
case "hello" => println("Bye")
}
val b: PartialFunction[Any, Unit] = a.orElse(PartialFunction.empty[Any, Unit])
a("hello") // "Bye"
a("bogus") // MatchError
b("bogus") // Nothing
b(true) // Nothing
makes sense but this is not how it is behaving and I am having a lot of trouble understanding why as the types signatures seem to indicate what I exposed above.
Here is a transcript of what I am observing with Scala 2.11.2:
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_11).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val a = PartialFunction[String, Unit] {
| case "hello" => println("Bye")
| }
a: PartialFunction[String,Unit] = <function1>
scala> a("hello")
Bye
scala> a("bye")
scala.MatchError: bye (of class java.lang.String)
at $anonfun$1.apply(<console>:7)
at $anonfun$1.apply(<console>:7)
at scala.PartialFunction$$anonfun$apply$1.applyOrElse(PartialFunction.scala:242)
at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:36)
... 33 elided
scala> val b = a.orElse(PartialFunction.empty[Any, Unit])
b: PartialFunction[String,Unit] = <function1>
scala> b("sdf")
scala.MatchError: sdf (of class java.lang.String)
at $anonfun$1.apply(<console>:7)
at $anonfun$1.apply(<console>:7)
at scala.PartialFunction$$anonfun$apply$1.applyOrElse(PartialFunction.scala:242)
at scala.PartialFunction$OrElse.apply(PartialFunction.scala:162)
... 33 elided
Note the return type of val b which has not widen the type of the PartialFunction.
But this also does not work as expected:
scala> val c = a.orElse(PartialFunction.empty[String, Unit])
c: PartialFunction[String,Unit] = <function1>
scala> c("sdfsdf")
scala.MatchError: sdfsdf (of class java.lang.String)
at $anonfun$1.apply(<console>:7)
at $anonfun$1.apply(<console>:7)
at scala.PartialFunction$$anonfun$apply$1.applyOrElse(PartialFunction.scala:242)
at scala.PartialFunction$OrElse.apply(PartialFunction.scala:162)
... 33 elided
There's a few things wrong with your attempt, but first let's see a working implementation:
scala> val a: PartialFunction[String, Unit] = { case "hello" => println("bye") }
a: PartialFunction[String,Unit] = <function1>
scala> val b: PartialFunction[Any, Unit] = { case _ => println("fallback") }
b: PartialFunction[Any,Unit] = <function1>
scala> val c = a.orElse(b)
c: PartialFunction[String,Unit] = <function1>
scala> c("hello")
bye
scala> c("foo")
fallback
There's two main errors in your code:
the way the PF is defined
the (wrong) assumption that empty is a "catch-all" function that returns Nothing
1. How to define a PartialFunction
val right: PartialFunction[String, Unit] = {
case "hello" => println("bye")
}
How not to define it:
val wrong = PartialFunction[String, Unit] {
case "hello" => println("bye")
}
If you look at the definition of PartialFunction.apply
def apply[A, B](f: A => B): PartialFunction[A, B] = { case x => f(x) }
you'll see that it defines a partial function for any x and it applies the given f function to it. Now your { case "hello" => println("bye") } is the f argument, so you approximately end up with the following (clearly unexpected) PartialFunction:
val wrong: PartialFunction[String, Unit] = {
case x => x match {
case "hello" => println("bye")
}
So when you ask whether it's defined it will always return true, since it's defined for any string:
wrong.isDefinedAt("hello") // true (ok)
wrong.isDefinedAt("whatever") // true (sure?)
but when you try to apply it
wrong("hello") // bye (ok)
wrong("whatever") // MatchError (BOOM!)
you fall short on the inner match.
Since orElse decides whether to call the "else" depending on the result of isDefined, then it's obvious why it fails.
2. Empty catches nothing!
Straight from the docs:
def empty[A, B]: PartialFunction[A, B]
The partial function with empty domain. Any attempt to invoke empty partial function leads to throwing scala.MatchError exception.
The PartialFunction (well, it's not really partial anymore) you're looking for is:
val fallback: PartialFunction[Any, Unit] = { case _ => println("fallback") }
or - just to show that we learn from our mistakes -
val fallback = PartialFunction[Any, Unit] { _ => println("fallback") }
You are using the PartialFunction object apply method which is defined so:
def apply[A, B](f: A => B): PartialFunction[A, B] = { case x => f(x) }
Basically it takes a function form A to B and automatically wrap it in a case statement, the problem is that you are passing the case too and I'm not 100% sure of what happens then, you can try passing a function to the apply or easily you can try without using the apply method:
scala> val a: PartialFunction[String, Unit] = {
| case "hello" => println("Bye")
| }
a: PartialFunction[String,Unit] = <function1>
scala> val b: PartialFunction[String, Unit] = {
| case _ => println("default")
| }
b: PartialFunction[String,Unit] = <function1>
scala> b("123")
default
You could also extend the trait and implement apply and isDefined as shown here.
PartialFunction.empty[A,B] is equivalent to:
{
case x: Nothing => x
}
(This typechecks, because Nothing is a subtype of both A and B.)
or, equivalently:
{
// note: this is probably not a valid Scala code for a partial function
// but, as PartialFunction.empty's name suggests, it's an *empty* block
}
This cannot match anything.
.orElse can be understood to simply concatenates lists of case statements from two PartialFunctions. So, in your case a.orElse(PartialFunction.empty[Any,Unit] means:
{ case "hello" => println("Bye") } orElse { /* no cases here */ }
which simplifies to:
{ case "hello" => println("Bye") }
or
{ case "hello" => println("Bye"); case x:Nothing => x }
MatchError is therefore obvious.
Note that the documetation also mentions that empty always throws MatchError.
From what I can guess, you wanted a PartialFunction that always matches. There's no named method in the standard library for that, but why should there be. You can simply write
{ case _ => () }
When I'm matching value of case classes, such as:
sealed abstract class Op
case class UOp[T, K](f: T => K) extends Op
case class BOp[T, Z, K](f: (T, Z) => K) extends Op
like this:
def f(op: Op): Int =
op match
{
case BOp(g) => g(1,2)
case UOp(g) => g(0)
}
the compiler infers it as
val g: (Nothing, Nothing) => Any
val g: Nothing => Any
Why am I getting Nothing as the type? Is it because of JVM type erasure? Are there elegant ways to match functions against variables?
I came up with this "hackish" solution, maybe there are other ways or cleaner ways to do this still without relying on reflection.
Define a few partial functions which will handle various args:
scala> val f: PartialFunction[Any, String] = { case (x: Int, y: String) => y * x }
f: PartialFunction[Any,String] = <function1>
scala> val g: PartialFunction[Any, String] = { case x: Int => x.toString }
g: PartialFunction[Any,String] = <function1>
scala> def h: PartialFunction[Any, BigDecimal] = { case (a: Int, b: Double, c: Long) => BigDecimal(a) + b + c }
h: PartialFunction[Any,BigDecimal]
scala> val l: List[PartialFunction[Any, Any]] = f :: g :: h :: Nil
l: List[PartialFunction[Any,Any]] = List(<function1>, <function1>, <function1>)
Check which functions can handle different inputs:
scala> l.map(_.isDefinedAt(1))
res0: List[Boolean] = List(false, true, false)
scala> l.map(_.isDefinedAt((1, "one")))
res1: List[Boolean] = List(true, false, false)
Given input find and apply a function:
scala> def applyFunction(input: Any): Option[Any] = {
| l find (_.isDefinedAt(input)) map (_ (input))
| }
applyFunction: (input: Any)Option[Any]
scala> applyFunction(1)
res1: Option[Any] = Some(1)
scala> applyFunction((2, "one"))
res2: Option[Any] = Some(oneone)
scala> applyFunction("one")
res3: Option[Any] = None
scala> applyFunction(1, 1.1, 9L)
res10: Option[Any] = Some(11.1)
This looks quite type unsafe and there must be better ways to do this.
I think magnet pattern should handle this well in more typesafe manner.
I have an heterogeneous List like the following one:
val l = List(1, "One", true)
and I need to filter its objects by extracting only the ones belonging to a given Class. For this purpose I wrote a very simple method like this:
def filterByClass[A](l: List[_], c: Class[A]) =
l filter (_.asInstanceOf[AnyRef].getClass() == c)
Note that I am obliged to add the explicit conversion to AnyRef in order to avoid this compilation problem:
error: type mismatch;
found : _$1 where type _$1
required: ?{val getClass(): ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method any2stringadd in object Predef of type (x: Any)scala.runtime.StringAdd
and method any2ArrowAssoc in object Predef of type [A](x: A)ArrowAssoc[A]
are possible conversion functions from _$1 to ?{val getClass(): ?}
l filter (_.getClass() == c)
However in this way the invocation of:
filterByClass(l, classOf[String])
returns as expected:
List(One)
but of course the same doesn't work, for example, with Int since they extends Any but not AnyRef, so by invoking:
filterByClass(l, classOf[Int])
the result is just the empty List.
Is there a way to make my filterByClass method working even with Int, Boolean and all the other classes extending Any?
The collect method already does what you want. For example to collect all Ints in a collection you could write
xs collect { case x: Int => x }
This of course only works when you hardcode the type but as primitives are handled differently from reference types it is actually better to do so. You can make your life easier with some type classes:
case class Collect[A](collect: PartialFunction[Any,A])
object Collect {
implicit val collectInt: Collect[Int] = Collect[Int]({case x: Int => x})
// repeat for other primitives
// for types that extend AnyRef
implicit def collectAnyRef[A <: AnyRef](implicit mf: ClassManifest[A]) =
Collect[A]({ case x if mf.erasure.isInstance(x) => x.asInstanceOf[A] })
}
def collectInstance[A : Collect](xs: List[_ >: A]) =
xs.collect(implicitly[Collect[A]].collect)
Then you can use it without even passing a Class[A] instance:
scala> collectInstance[Int](l)
res5: List[Int] = List(1)
scala> collectInstance[String](l)
res6: List[String] = List(One)
Using isInstanceOf:
scala> val l = List(1, "One", 2)
l: List[Any] = List(1, One, 2)
scala> l . filter(_.isInstanceOf[String])
res1: List[Any] = List(One)
scala> l . filter(_.isInstanceOf[Int])
res2: List[Any] = List(1, 2)
edit:
As the OP requested, here's another version that moves the check in a method. I Couldn't find a way to use isInstanceOf and so I changed the implementation to use a ClassManifest:
def filterByClass[A](l: List[_])(implicit mf: ClassManifest[A]) =
l.filter(mf.erasure.isInstance(_))
Some usage scenarios:
scala> filterByClass[String](l)
res5: List[Any] = List(One)
scala> filterByClass[java.lang.Integer](l)
res6: List[Any] = List(1, 2)
scala> filterByClass[Int](l)
res7: List[Any] = List()
As can be seen above, this solution doesn't work with Scala's Int type.
The class of an element in a List[Any] is never classOf[Int], so this is behaving as expected. Your assumptions apparently leave this unexpected, but it's hard to give you a better way because the right way is "don't do that."
What do you think can be said about the classes of the members of a heterogenous list? Maybe this is illustrative. I'm curious how you think java does it better.
scala> def f[T: Manifest](xs: List[T]) = println(manifest[T] + ", " + manifest[T].erasure)
f: [T](xs: List[T])(implicit evidence$1: Manifest[T])Unit
scala> f(List(1))
Int, int
scala> f(List(1, true))
AnyVal, class java.lang.Object
scala> f(List(1, "One", true))
Any, class java.lang.Object
This worked for me. Is this what you want?
scala> val l = List(1, "One", true)
l: List[Any] = List(1, One, true)
scala> l filter { case x: String => true; case _ => false }
res0: List[Any] = List(One)
scala> l filter { case x: Int => true; case _ => false }
res1: List[Any] = List(1)
scala> l filter { case x: Boolean => true; case _ => false }
res2: List[Any] = List(true)
Despite my solution could be less elegant than this one I find mine quicker and easier. I just defined a method like this:
private def normalizeClass(c: Class[_]): Class[_] =
if (classOf[AnyRef].isAssignableFrom((c))) c
else if (c == classOf[Int]) classOf[java.lang.Integer]
// Add all other primitive types
else classOf[java.lang.Boolean]
So by using it in my former filterByClass method as it follows:
def filterByClass[A](l: List[_], c: Class[A]) =
l filter (normalizeClass(c).isInstance(_))
the invocation of:
filterByClass(List(1, "One", false), classOf[Int])
just returns
List(1)
as expected.
At the end, this problem reduces to find a map between a primitive and the corresponding boxed type.
Maybe a help can arrive from scala.reflect.Invocation (not included in the final version of 2.8.0), the getAnyValClass function in particular (here slightly edited)
def getAnyValClass(x: Any): java.lang.Class[_] = x match {
case _: Byte => classOf[Byte]
case _: Short => classOf[Short]
case _: Int => classOf[Int]
case _: Long => classOf[Long]
case _: Float => classOf[Float]
case _: Double => classOf[Double]
case _: Char => classOf[Char]
case _: Boolean => classOf[Boolean]
case _: Unit => classOf[Unit]
case x#_ => x.asInstanceOf[AnyRef].getClass
}
With this function the filter is as easy as
def filterByClass[T: Manifest](l:List[Any]) = {
l filter (getAnyValClass(_) == manifest[T].erasure)
}
and the invocation is:
filterByClass[Int](List(1,"one",true))