I have the following code:
class CSplit(var s1: CanvNode, var s2: CanvNode) extends SplitPane
{
topComponent = s1.merge
bottomComponent = s2.merge
def containsV(orig: MapCanvT): Option[MapCanvT] =
{
def containsIn(cn: CanvNode): Option[MapCanvT] = cn match
{
case Left => None
case Right(mc) => if (mc == orig) Some(mc) else None
}
containsIn(s1) match
{
case Some(mc) => Some(mc)
case None => containsIn(s2)
}
}
}
I want to reduce the code of the containsV method. My first thought was to use a fold method to shorten the containsIn method. But Option doesn't have one, nor does it extend Class Either. Shouldn't Option[T] extend Either[T, None] ? Then at least one could use Either's fold method.
My final thought was to treat s1 and s2 as a List and do find over it but I can't get this to compile:
def containsV(orig: MapCanvT):
Option[MapCanvT] = ::[CanvNode](s1, s2).find(_ == Right(orig))
Scala 2.10 adds fold to Option. In the meantime you can use map(f).getOrElse(g) instead:
// These produce identical results
o.fold(g)(x => f(x))
o.map(x => f(x)).getOrElse(g)
Edit: so, for example, the following three do the same thing:
val os: List[Option[Int]] = List(Some(5),None)
// Explicit match
os.map{ _ match {
case Some(x) => x+3
case None => 0
}}
// map+getOrElse
os.map{ _.map(_+3).getOrElse(0) }
// fold
os.map{ _.fold(0)(_+3) }
In the fold case, you give the default value for the None case first, and then the function that handles the case where there is a value. In each case you should get List(8,0).
It can be implemented with a list by using the collectFirst method
def containsV(orig: MapCanvT): Option[MapCanvT]
= List(s1, s2).collectFirst {case i: MapCanvT if (i == (orig) => i}
Let's start with the easy part:
containsIn(s1) match
{
case Some(mc) => Some(mc)
case None => containsIn(s2)
}
is the same as
containsIn(s1) orElse containsIn(s2)
Now we only have to deal with containsIn:
def containsIn(cn: CanvNode): Option[MapCanvT] = cn match
{
case Left => None
case Right(mc) => if (mc == orig) Some(mc) else None
}
We can use fold on Either, which gets rid of most of the pattern matching:
cn.fold(_ => None, Some(_))
But there's the orig thingy. We can handle it with a filter, though:
cn.fold(_ => None, Some(_)) filter (orig.==)
Thus:
def containsV(orig: MapCanvT): Option[MapCanvT] = {
def containsIn(cn: CanvNode): Option[MapCanvT] =
cn.fold(_ => None, Some(_)) filter (orig.==)
containsIn(s1) orElse containsIn(s2)
}
I think orElse is much overlooked.
Related
What is the higher order function equivalent expression to the following?
def isRepeated:Boolean = {
prev match {
case Some(a) => a.prev match {
case Some(b) => b.equals(this)
case None => false
}
case None => false
}
}
I believe this is equivalent:
def isRepeated:Boolean = prev.exists(_.prev.exists(_.equals(this)))
I have a function that as a parameter takes an object and if it is of the correct type I need to access the last element in an Option[List[Int]]. I have a working solution but it seems clumsy. In the case that there are not any items in obj.listOfThings I will need to have i have the value 0. Is there a better way to achieve this?
val i = foo match {
case obj: Bar =>
obj.listOfInts match {
case Some(ints) =>
ints.last
case _ =>
0
}
case _ =>
0
}
Technically it could return an Option[Int]. I'm still pretty new to Scala and would like to learn better approaches to this sort of problems.
In your case initially it seems that what Ende Neu suggested is the right way to go:
val i = foo match {
case obj: Bar =>
obj.listOfInts.map(_.last /* This throws an exception when the list is empty*/).getOrElse(0)
case _ =>
0
}
But if you look into it you'll see that you have a bug in your code, in the case that that obj.listOfInts is Some(Nil), because in that case you get a NoSuchElementException for trying to call last on an empty List.
Try this code with foo = Bar(Some(Nil)) and see for yourself.
When you use Option[List] think very carefully if this is what you want.
Usually after some thinking you will scrap the Option and just stay with a List because the Option serves no purpose.
I worked with many developers who misuse Option[List] because of not understanding the similarities between Nil and None and usually the 'None' case ends up playing the same role as Some(Nil)
So you end up having to do this:
optionalList match {
case None => // do something
case Some(list) =>
list match {
case Nil => // do the same thing
case head::tail => // do other stuff
}
}
As you can see the None case and the Some(Nil) case are basically the same.
To fix your bug you should do:
case class Bar(listOfInts: Option[List[Int]])
val i = foo match {
case Bar(Some(list)) if list != Nil => list.last
case _ => 0
}
You probably want to use flatMap and lastOption here:
obj.listOfInts.flatMap(_.lastOption)
In case listOfInts is None, or it is Some(Nil), this will return None. Otherwise it will return the last element. If you want to return 0 instead of None, just use getOrElse:
obj.listOfInts.flatMap(_.lastOption).getOrElse(0)
If you wanted to use a match, you could do:
obj.listOfInts match {
case Some(list#(hd::tl)) => list.last
case _ => 0
}
Here, the hd::tl guarantees that list is not empty. Another option is use a conditional match:
obj.listOfInts match {
case Some(list) if list.nonEmpty => list.last
case _ => 0
}
Or to match the None and Some(Nil) cases first:
obj.listOfInts match {
case None | Some(Nil) => 0
case Some(list) => list.last
}
As suggested in the comments, I think the best way to go is:
val i = foo match {
case obj: Bar => obj.listOfInts.map(_.last).getOrElse(0)
case _ => 0
}
More concise way including the instanceof:
scala> case class B(is: Option[List[Int]])
defined class B
scala> def f(x: Any) = Option(x) collect { case b: B => b.is flatMap (_.lastOption) } flatten
f: (x: Any)Option[Int]
scala> f(B(Option(5 to 7 toList)))
res0: Option[Int] = Some(7)
or
scala> import PartialFunction.{ condOpt => when }
import PartialFunction.{condOpt=>when}
scala> def g(x: Any) = when(x) { case b: B => b.is flatMap (_.lastOption) } flatten
g: (x: Any)Option[Int]
scala> g(B(Option(5 to 7 toList)))
res1: Option[Int] = Some(7)
It's probably worth asking why you lost static type info, that you need to pattern match.
There is a list with type List[Option[String]], it may contain Some or None
val list:List[Option[String]] = List(Some("aaa"), None, Some("bbb"))
list match {
case /*List with all Some*/ => println("all items are Some")
case /*List with all None*/ => println("all items are None")
case /*List with Some and None*/ => println("Contain both Some and None")
}
But I don't know how to write it. Is it possible to use pattern matching?
You can write custom extractors:
object AllSome {
def unapply[T](l: List[Option[T]]) = l.forall(_.isDefined)
}
object AllNone {
def unapply[T](l: List[Option[T]]) = l.forall(_ == None)
}
object Mixed {
def unapply[T](l: List[Option[T]]) = !AllNone.unapply(l) && !AllSome.unapply(l)
}
And use them like:
list match {
case AllSome() => ???
case AllNone() => ???
case Mixed() => ???
}
One approach involves flattening the list and comparing the resulting length with the original length, like this,
list.flatten.length match {
case 0 => println("All items are None")
case len if len < l.length => println("Contain both Some and None")
case _ => println("All items are Some")
}
Update
To get the contents of each Some, simply list.flatten , namely for instance,
list.flatten
res: List(aaa, bbb)
and
List().flatten
res: List[Nothing] = List()
If you really want a solution with well-defined semantics and based on pattern matching you could do something as follows:
abstract class CollectionStatus
case object Empty extends CollectionStatus
case object AllSome extends CollectionStatus
case object AllNone extends CollectionStatus
case object Mixed extends CollectionStatus
object CollectionStatus {
def default: CollectionStatus = Empty
}
def folder(status: CollectionStatus, o: Option[_]): CollectionStatus = {
(status, o) match {
case (Empty, Some(_)) => AllSome
case (Empty, None) => AllNone
case (AllSome, Some(_)) => AllSome
case (AllNone, None) => AllNone
case _ => Mixed
}
}
Here's how I would use it:
List[Option[String]]().foldLeft(CollectionStatus.default)(folder _) //Empty
List(Option("foo"), Option("bar")).foldLeft(CollectionStatus.default)(folder _) //AllSome
List(Option("foo"), None).foldLeft(CollectionStatus.default)(folder _) //Mixed
List(None, None).foldLeft(CollectionStatus.default)(folder _) //AllNone
This could be further improved by replacing foldLeft with a tail recursive function that would accumulate the status of the list, and finish its computations without traversing the whole list if it recognized the list was "Mixed" already:
import scala.annotation.tailrec
def listStatus(list: List[Option[_]]): CollectionStatus = {
#tailrec
def inner(acc: CollectionStatus, ls: List[Option[_]]): CollectionStatus = {
acc match {
case Mixed => Mixed
case s => {
ls match {
case Nil => s
case h :: t => {
inner(folder(s, h), t)
}
}
}
}
}
inner(CollectionStatus.default, list)
}
val l: List[Option[String]] = List(Some("aaa"), None, Some("bbb"))
l.groupBy({
case Some(_) => "s"
case None => "n"
}).toList match {
case List(_,_) => println("both")
case List(a) => if( a._1 == "n") println("none") else println("some")
}
I want to check the type of the parameters of a method, but I don't know the best way to do this. See my code:
class X {
def x(a: Int, b: String) {}
}
val methods = classOf[X].getDeclaredMethods
methods map { m =>
m.getParameterTypes.toList map { t =>
println(t.getName)
// I don't know how to write the following
if ( the type of t is Int) { do something}
else if( the type of t is String ) { do something}
else { }
}
}
Please note the comment in the code. I don't know how to check the types in scala way.
I've tried:
t match {
case _:String => println("### is a string")
case _:Int => println("### is an int")
case _ => println("### ?")
}
But it can't be compiled.
I can use java-way to check:
if (t.isAssignableFrom(classOf[String])) // do something
else if(t.isAssignableFrom(classOf[Int])) // do something
else {}
It seems we should use it in scala, right?
UPDATE:
If I want to use match, I should write like this:
t match {
case i if i.isAssignableFrom(classOf[Int]) => println("### is an Int")
case s if s.isAssignableFrom(classOf[String]) => println("### is a String")
case _ => println("###?")
}
Is it the best answer?
I could make it work with t as a type by defining the cases as constants. It wouldn't compile with the class literals as the case expression. Try:
val S = classOf[String]
val I = classOf[Int]
t match {
case S => println("### is a string")
case I => println("### is an int")
case _ => println("### ?")
}
You can use ClassManifest.fromClass to correctly handle the coercion of primitives to AnyVals, and any other such troubles you might have encountering boxed vs unboxed types when getting funky with reflection.
Like this:
import reflect.ClassManifest
class Wibble { def method(a:Int, b: String) = () }
for(method <- classOf[Wibble].getDeclaredMethods; paramType <- method.getParameterTypes) {
ClassManifest.fromClass(paramType) match {
case m if m <:< ClassManifest.Int => println("Interiffic")
case m if m <:< ClassManifest.Float => println("Floaty, like butterflies")
case m if m <:< ClassManifest.Double => println("Or Quits...")
//todo: all the other AnyVal types...
case m if m <:< classManifest[String] => println("bleeding edge physics, yeah baby!")
//...and a default condition
}
}
How would you implement class that parses some input via regex and transforms founded string to some other type? My approach is:
class ARegex[T](regex:Regex, reform:Option[String => T]){
def findFirst(input:String):Option[T] = {
(regex.findFirstIn(input), reform) match{
case (None, _) => None
case (Some(s), None) => Some(s) // this won't compile because of type mismatch
case (Some(s), Some(fun)) => Some(fun(s))
}
}
}
class BRegex[T](regex:Regex, reform:Option[String => T]) {
def findFirst(input:String) = { //returns Option[Any] - erasure
(regex.findFirstIn(input), reform) match{
case (None, _) => None
case (Some(s), None) => Some(s)
case (Some(s), Some(fun)) => Some(fun(s))
}
}
}
We can solve this problem by eliminating the Option part of the reform's type, and using a different mechanism to indicate that we don't want to change the match in any way. This mechanism is to use identity as a default parameter or pass identity when you don't want the type to change.
class ARegex[T](regex:Regex, reform:String => T = identity[String](_)){
def findFirst(input:String):Option[T] = {
regex.findFirstIn(input) match{
case None => None
case Some(s) => Some(reform(s))
}
}
}
new ARegex("something".r).findFirst("something else") //returns Option[String]
new ARegex("3".r, {x=>x.toInt}).findFirst("number 3") //returns Option[Int]
Well, the problem is the type mismatch, because you are returning either a String or a T, which, of course, are unified at Any. You can't say you are going to return Option[T] and then return Option[String].
Other than that, a simplified version of that code is this:
class ARegex[T](regex: Regex, reform: Option[String => T]) {
def findFirst(input: String): Option[Any] =
regex findFirstIn input map { s => reform map (_(s)) getOrElse s }
}
You could return an Option[Either[String, T]], though. The code would look like this:
class ARegex[T](regex: Regex, reform: Option[String => T]) {
def findFirst(input: String): Option[Either[String, T]] =
regex findFirstIn input map { s => reform map (_(s)) toRight s }
}
Why is reform Option[String => T] instead of just String => T? If you don't pass in a mechanism for creating an instance of your desired type, there's no mechanism for the runtime system to actually create the appropriate object. If you really need to pass in an Option[String => T] then your second case should simply return None.
Also, flatMap is your friend, and will give you the correct behavior (i.e. if reform is None, the method returns None.
class RegexExtractor[T](regex: Regex, reform: Option[String => T]) {
def findFirst(input: String): Option[T] = reform.flatMap(f => regex.findFirstIn(input).map(f))
}