I was experimenting with the following code;
(for (f <- (new File(".")).listFiles() if !f.isDirectory) yield f) match {
case x:File => println(x.getAbsoluteFile)
case _ => println(_)
}
Obviously I am wrong somehow, as I am getting the following Error
scrutinee is incompatible with pattern type;
found : java.io.File
required: Array[java.io.File]
case x:File => println(x.getAbsoluteFile)
^
What I was trying to do is pretty obvious; I tried to get each yielded value from the for-loop and pass it to a match-case "filter". I am not interesting in writing a better File tree filter rather than knowing the reason of the Error that I am getting and if it is possible to fix it (or rewrite somehow else).
Cheers!
Just a few symbols away:
for (f <- (new File(".")).listFiles() if !f.isDirectory) f match {
case x:File => println(x.getAbsoluteFile)
case _ => println(_)
}
The diff is
yield f)
{ f
In your case you're first processing (listing|filtering|yielding one-by-one) whole collection and only then match whole result.
Related
I am new to Scala's Set. I was trying to concatenate a Set with an empty Set. The code follows:
def getAllSlots(preferences: Map[Band, List[Slot]]): Set[Slot] = {
preferences.foldLeft(Set.empty){(r,c) => c match {
case (_, li) => li.toSet ++ r
case _ => r
}}
}
The error happened when I am trying to do li.toSet ++ r, complaining that ... doesn't conform to expected type Set[Nothing]. Then, I have no idea how to build up a Set starting from an empty one.
Thanks everyone.
You have to help the compiler to infer the right type, it doesn't have enough informations to figure out that you mean Set[Slot], empty takes a type parameter:
def getAllSlots(preferences: Map[Band, List[Slot]]): Set[Slot] = {
preferences.foldLeft(Set.empty[Slot]){(r,c) => c match {
case (_, li) => li.toSet ++ r
case _ => r
}}
}
Simpler and neat Solution
preferences.valuesIterator.flatten.toSet
Get all the values of the preferences map using valuesIterator and then flatten and then convert to set using toSet function.
getAllSlots function becomes
def getAllSlots(preferences: Map[Band, List[Slot]]): Set[Slot] =
preferences.valuesIterator.flatten.toSet
This code compiles fine, but fails at runtime:
val values = Set("a").toSeq.sorted
values match {
case Nil => println("empty")
case h::t => println(s"h = $h")
}
With the error message:
scala.MatchError: ArrayBuffer(a) (of class scala.collection.mutable.ArrayBuffer)
I understand that somewhere in the process an ArrayBuffer is created, on which I cannot pattern-match like this. However, why can't the compiler tell me that this is not going to work?
You are matching on an open (extensible) data type, Scala's Seq. It could be a List, so Scala doesn't complain with your List pattern. On the other hand, exhaustiveness cannot be checked because it could really be any class implementing Seq (that we may not even know statically), so Scala just trusts you on this one.
You can use generic Seq patterns instead:
values match {
case Seq() => println("empty")
case h +: t => println(s"h = $h")
}
Or just convert to a List and use the same patterns (but Lists are not very efficient data structures, so it's probably better with the first option).
val values = Set("a").toList.sorted
values match {
case Nil => println("empty")
case h::t => println(s"h = $h")
}
Getting errors from pattern matching can be tricky sometimes, but in this case:
scala> :type values
Seq[String]
scala> Seq(1,2,3) match { case h::t => "ok" }
res1: String = ok
There's not enough type info to say it can't work, and it errs on the side of not annoying you.
def flatten(l: List[_]): List[_] = {
def iflatten(l: List[_], ret: List[_]): List[_] = l match {
case Nil => ret
case h :: Nil =>
if( h.isInstanceOf[List[_]]) { iflatten(h, ret) }
else {
l.head :: ret
iflatten(l.tail, ret)
}
}
}
I know there are multiple ways to do this, and I'm not 100% sure my way is correct. I would like to test it but one issue I'm running into is in the second case statement where I call:
... { iflatten(h, ret) }
I am getting the compiler error:
error: type mismatch;
found : Unit
required: List[?]
I'm trying to work through these type issues to learn more about the typesystem as it's different than what I've worked with in the past. Any suggestions as to why the compiler is complaining would be greatly appreciated.
I'm not getting the same error you are concerning iflatten(h,ret).
I am getting the found : Unit; required : List[?] error, but it refers to the fact that you are not calling iflatten in flatten itself : after defining it, you need to call the function at the end of flatten's definition.
def flatten(l: List[_]): List[_] = {
def iflatten(l: List[_], ret: List[_]): List[_] = l match {
case Nil => ret
case (h:List[_]) :: tail => iflatten(tail,iflatten(h,ret))
case h :: tail => iflatten(tail,h::ret)
}
iflatten(l,List()).reverse
}
As for the code itself, you can (and should) verify types when matching.
Also note that the case h :: Nil only matches 1-length list.
As for the algorithm, you need to call iflatten within itself (that's where the arbitrarily nesting takes place).
I think you're just missing a cast.
if( h.isInstanceOf[List[_]]) { iflatten(h.asInstanceOf[List[_]], ret) }
Alternately: It would be prettier with pattern matching.
h match {
case hList: List[_] =>
iflatten(hList, ret)
case _ =>
l.head :: ret
iflatten(l.tail, ret)
}
(caveat: This is just off the top of my head and I haven't put anything through a compiler)
edit - Marth's solution of merging that into the previous pattern match looks better than mine.
Actually, I suspect the problem lies in the fact that you define the inner method iflatten, but never call it, so that the outer method flatten doesn't return anything (ie defaults to a return type of Unit, conflicting with the stated return type of List[_]).
Try adding the following as the last line of the outer flatten method:
iflatten(l, Nil)
Beyond that, you have various other problems with your code, such as not handling all match cases: you handle the case of a list with one element - h :: Nil - but not several elements. You probably meant something like h :: theRest, and then use theRest somewhere - probably as your ret parameter for the recursive call.
You also use the check h.isInstanceOf[List[_]] (generally any use of isInstanceOf is a bad code smell in scala) but then try passing h into iflatten recursively without casting it as List[_] (for example, as in #ChristopherMartin's answer, although using asInstanceOf is an even bigger code smell). #Marth's answer gives a good example of how to avoid these explicit type checks.
I think this is something the Shapeless library is good at.
https://github.com/milessabin/shapeless/blob/master/examples/src/main/scala/shapeless/examples/flatten.scala
Sorry, but this code is very complicated. I tried to simplify it and got to this solution:
scala> :paste
// Entering paste mode (ctrl-D to finish)
def flatten(l : List[_]) : List[_] = l flatMap {
case l1 : List[_] => flatten(l1)
case otherwise => List(otherwise)
}
// Exiting paste mode, now interpreting.
flatten: (l: List[_])List[_]
scala> flatten(List(1,2,3))
res3: List[Any] = List(1, 2, 3)
scala> flatten(List(1,2,List(3,4)))
res4: List[Any] = List(1, 2, 3, 4)
scala> flatten(List(List(1,List(2),3),4,List(4,5)))
res5: List[Any] = List(1, 2, 3, 4, 4, 5)
After fixing the code (adding the call to iflat), I did the following refactorings:
Removed the inner method
Used the built in flatMap for the iteration (and hence could eliminate or simplify some case expressions)
Replaced the instanceOf with type guards
I think a simpler solution would be using the shapeless library (hint: look for the "boilerplate" part).
I have a Scala Option[T]. If the value is Some(x) I want to process it with a a process that does not return a value (Unit), but if it is None, I want to print an error.
I can use the following code to do this, but I understand that the more idiomatic way is to treat the Option[T] as a sequence and use map, foreach, etc. How do I do this?
opt match {
case Some(x) => // process x with no return value, e.g. write x to a file
case None => // print error message
}
I think explicit pattern matching suits your use case best.
Scala's Option is, sadly, missing a method to do exactly this. I add one:
class OptionWrapper[A](o: Option[A]) {
def fold[Z](default: => Z)(action: A => Z) = o.map(action).getOrElse(default)
}
implicit def option_has_utility[A](o: Option[A]) = new OptionWrapper(o)
which has the slightly nicer (in my view) usage
op.fold{ println("Empty!") }{ x => doStuffWith(x) }
You can see from how it's defined that map/getOrElse can be used instead of pattern matching.
Alternatively, Either already has a fold method. So you can
op.toRight(()).fold{ _ => println("Empty!") }{ x => doStuffWith(x) }
but this is a little clumsy given that you have to provide the left value (here (), i.e. Unit) and then define a function on that, rather than just stating what you want to happen on None.
The pattern match isn't bad either, especially for longer blocks of code. For short ones, the overhead of the match starts getting in the way of the point. For example:
op.fold{ printError }{ saveUserInput }
has a lot less syntactic overhead than
op match {
case Some(x) => saveUserInput(x)
case None => printError
}
and therefore, once you expect it, is a lot easier to comprehend.
I'd recommend to simply and safely use opt.get which itself throws a NoSuchElementException exception if opt is None. Or if you want to throw your own exception, you can do this:
val x = opt.getOrElse(throw new Exception("Your error message"))
// x is of type T
as #missingfaktor says, you are in the exact scenario where pattern matching is giving the most readable results.
If Option has a value you want to do something, if not you want to do something else.
While there are various ways to use map and other functional constructs on Option types, they are generally useful when:
you want to use the Some case and ignore the None case e.g. in your case
opt.map(writeToFile(_)) //(...if None just do nothing)
or you want to chain the operations on more than one option and give a result only when all of them are Some. For instance, one way of doing this is:
val concatThreeOptions =
for {
n1 <- opt1
n2 <- opt2
n3 <- opt3
} yield n1 + n2 + n3 // this will be None if any of the three is None
// we will either write them all to a file or none of them
but none of these seem to be your case
Pattern matching is the best choice here.
However, if you want to treat Option as a sequence and to map over it, you can do it, because Unit is a value:
opt map { v =>
println(v) // process v (result type is Unit)
} getOrElse {
println("error")
}
By the way, printing an error is some kind of "anti-pattern", so it's better to throw an exception anyway:
opt.getOrElse(throw new SomeException)
I have a recursive function that takes a Map as single parameter. It then adds new entries to that Map and calls itself with this larger Map. Please ignore the return values for now. The function isn't finished yet. Here's the code:
def breadthFirstHelper( found: Map[AIS_State,(Option[AIS_State], Int)] ): List[AIS_State] = {
val extension =
for(
(s, v) <- found;
next <- this.expand(s) if (! (found contains next) )
) yield (next -> (Some(s), 0))
if ( extension.exists( (s -> (p,c)) => this.isGoal( s ) ) )
List(this.getStart)
else
breadthFirstHelper( found ++ extension )
}
In extension are the new entries that shall get added to the map. Note that the for-statement generates an iterable, not a map. But those entries shall later get added to the original map for the recursive call. In the break condition, I need to test whether a certain value has been generated inside extension. I try to do this by using the exists method on extension. But the syntax for extracting values from the map entries (the stuff following the yield) doesn't work.
Questions:
How do I get my break condition (the boolean statement to the if) to work?
Is it a good idea to do recursive work on a immutable Map like this? Is this good functional style?
When using a pattern-match (e.g. against a Tuple2) in a function, you need to use braces {} and the case statement.
if (extension.exists { case (s,_) => isGoal(s) } )
The above also uses the fact that it is more clear when matching to use the wildcard _ for any allowable value (which you subsequently do not care about). The case xyz gets compiled into a PartialFunction which in turn extends from Function1 and hence can be used as an argument to the exists method.
As for the style, I am not functional programming expert but this seems like it will be compiled into a iterative form (i.e. it's tail-recursive) by scalac. There's nothing which says "recursion with Maps is bad" so why not?
Note that -> is a method on Any (via implicit conversion) which creates a Tuple2 - it is not a case class like :: or ! and hence cannot be used in a case pattern match statement. This is because:
val l: List[String] = Nil
l match {
case x :: xs =>
}
Is really shorthand/sugar for
case ::(x, xs) =>
Similarly a ! b is equivalent to !(a, b). Of course, you may have written your own case class ->...
Note2: as Daniel says below, you cannot in any case use a pattern-match in a function definition; so while the above partial function is valid, the following function is not:
(x :: xs) =>
This is a bit convoluted for me to follow, whatever Oxbow Lakes might think.
I'd like first to clarify one point: there is no break condition in for-comprehensions. They are not loops like C's (or Java's) for.
What an if in a for-comprehension means is a guard. For instance, let's say I do this:
for {i <- 1 to 10
j <- 1 to 10
if i != j
} yield (i, j)
The loop isn't "stopped" when the condition is false. It simply skips the iterations for which that condition is false, and proceed with the true ones. Here is another example:
for {i <- 1 to 10
j <- 1 to 10
if i % 2 != 0
} yield (i, j)
You said you don't have side-effects, so I can skip a whole chapter about side effects and guards on for-comprehensions. On the other hand, reading a blog post I made recently on Strict Ranges is not a bad idea.
So... give up on break conditions. They can be made to work, but they are not functional. Try to rephrase the problem in a more functional way, and the need for a break condition will be replaced by something else.
Next, Oxbow is correct in that (s -> (p,c) => isn't allowed because there is no extractor defined on an object called ->, but, alas, even (a :: b) => would not be allowed, because there is no pattern matching going on in functional literal parameter declaration. You must simply state the parameters on the left side of =>, without doing any kind of decomposition. You may, however, do this:
if ( extension.exists( t => val (s, (p,c)) = t; this.isGoal( s ) ) )
Note that I replaced -> with ,. This works because a -> b is a syntactic sugar for (a, b), which is, itself, a syntactic sugar for Tuple2(a, b). As you don't use neither p nor c, this works too:
if ( extension.exists( t => val (s, _) = t; this.isGoal( s ) ) )
Finally, your recursive code is perfectly fine, though probably not optimized for tail-recursion. For that, you either make your method final, or you make the recursive function private to the method. Like this:
final def breadthFirstHelper
or
def breadthFirstHelper(...) {
def myRecursiveBreadthFirstHelper(...) { ... }
myRecursiveBreadthFirstHelper(...)
}
On Scala 2.8 there is an annotation called #TailRec which will tell you if the function can be made tail recursive or not. And, in fact, it seems there will be a flag to display warnings about functions that could be made tail-recursive if slightly changed, such as above.
EDIT
Regarding Oxbow's solution using case, that's a function or partial function literal. It's type will depend on what the inference requires. In that case, because that's that exists takes, a function. However, one must be careful to ensure that there will always be a match, otherwise you get an exception. For example:
scala> List(1, 'c') exists { case _: Int => true }
res0: Boolean = true
scala> List(1, 'c') exists { case _: String => true }
scala.MatchError: 1
at $anonfun$1.apply(<console>:5)
... (stack trace elided)
scala> List(1, 'c') exists { case _: String => true; case _ => false }
res3: Boolean = false
scala> ({ case _: Int => true } : PartialFunction[AnyRef,Boolean])
res5: PartialFunction[AnyRef,Boolean] = <function1>
scala> ({ case _: Int => true } : Function1[Int, Boolean])
res6: (Int) => Boolean = <function1>
EDIT 2
The solution Oxbow proposes does use pattern matching, because it is based on function literals using case statements, which do use pattern matching. When I said it was not possible, I was speaking of the syntax x => s.