I found a strange working construct in scala:
(ArrayBuffer[Int]():Seq[Int]) match {
case Nil => "whoo"
case _ => "nayyy"
}
which returns
"whoo"
Apparently this already works partially for Vectors, but not pattern matching. can someone explain me that? Nil does not have any method named unapply. How is this possible?
With objects, unapply is not involved (that would be the case if you had used the hypothetical case Nil() => ...). Instead, the equality is checked using the equals method.
Equality for collections is defined in terms of their elements. E.g.
List(1,2,3) == Vector(1,2,3) // true!
The same happens with Nil which equals any empty sequence:
Vector() == Nil // true
collection.mutable.ArrayBuffer() == Nil // true
Related
I recently fell over a scala pattern match, that looked more or less like this:
def func (li :List[Int]): List[Int] = li match {
case Nil => Nil
case start :+ tail => start
case List() => li
}
Now, what these three different cases return is not so much what I am in interesed about.
I wondering whether a pattern match like this would ever have any effect? Is there any case at all, where third case could ever reached?
My initial thought is no, since all lists with more than 0 elements will always match on the first case, and therefore the second case could never be reached
You can read the post: Scala: Nil vs List(). From the point of view of pattern matching, they are the same. The third case will never hit.
In Scala source code you can find that case object Nil extends List[Nothing], and that empty list is Nil.
The third case is redundant, because as far as I know, an empty list can only ever be Nil. List is sealed, so there won't be classes other than :: and the object Nil extending it.
However, a list with more than 0 elements will always match on the second case. A list with no elements would match the first case (and the third case, if the first were not present).
When working in Scala, I often want to parse a field of type [A] and convert it to a Option[A], with a single case (for example, "NA" or "") being converted to None, and the other cases being wrapped in some.
Right now, I'm using the following matching syntax.
match {
case "" => None
case s: String => Some(s)
}
// converts an empty String to None, and otherwise wraps it in a Some.
Is there any more concise / idiomatic way to write this?
There are a more concise ways. One of:
Option(x).filter(_ != "")
Option(x).filterNot(_ == "")
will do the trick, though it's a bit less efficient since it creates an Option and then may throw it away.
If you do this a lot, you probably want to create an extension method (or just a method, if you don't mind having the method name first):
implicit class ToOptionWithDefault[A](private val underlying: A) extends AnyVal {
def optNot(not: A) = if (underlying == not) None else Some(underlying)
}
Now you can
scala> 47.toString optNot ""
res1: Option[String] = Some(47)
(And, of course, you can always create a method whose body is your match solution, or an equivalent one with if, so you can reuse it for that particular case.)
I'd probably use filterNot here:
scala> Option("hey").filterNot(_ == "NA")
res0: Option[String] = Some(hey)
scala> Option("NA").filterNot(_ == "NA")
res1: Option[String] = None
It requires you to think of Option as a collection with one or zero elements, but if you get into that habit it's reasonably clear.
A simple and intuitive approach includes this expression,
if (s.isEmpty) None else Some(s)
This assumes s labels the value to be otherwise matched (thanks to #RexKerr for the note).
Is there any special case class for representing an empty ArrayBuffer that can be used in pattern matching similar to Nil for lists?
Also why this works:
scala> collection.mutable.ArrayBuffer.empty == Nil
res11: Boolean = true
While this does not:
scala> collection.mutable.ArrayBuffer() match { case Nil => 1 }
<console>:8: error: pattern type is incompatible with expected type;
found : scala.collection.immutable.Nil.type
required: scala.collection.mutable.ArrayBuffer[Nothing]
UPDATE
After giving it some thought I presume there is no such a case class. While existence of Nil is vital for List to work, no special structure of this kind is needed for arrays.
I've found a workaround for empty match check that might work in most cases:
collection.mutable.ArrayBuffer(2) match {
case collection.mutable.ArrayBuffer(v, _*) => v * 2
case _ => 0
}
I first check if array has at least one element and otherwise it should be empty.
Also as it turns out I could just use ArrayBuffer.isEmpty instead of pattern match.
Jasper-M provided a good answer to your second question (why == works but pattern matching fails).
As to your first, there is no equivalent to Nil for ArrayBuffer. The reason is that List is defined using scala's notion of Algebraic Data Types (ADT), while ArrayBuffer is not.
Take a look at the source for ArrayBuffer. It's implemented as a regular class, whereas List is implemented as an abstract class with two subclasses: a case object Nil, and a case class ::.
These case classes are what allow you to pattern match on List. Since there's no equivalent for ArrayBuffer, you cannot pattern match.
scala> collection.mutable.ArrayBuffer.empty == Nil
res11: Boolean = true
The reason this is true can be found by looking at the documentation of the equals method:
true if that is a sequence that has the same elements as this sequence
in the same order, false otherwise
For instance:
scala> val buffer = collection.mutable.ArrayBuffer.empty[Int]
buffer: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()
scala> buffer.append(4)
scala> buffer == List(4)
res1: Boolean = true
So that has nothing to do with pattern matching.
After giving it some thought I presume there is no such a case class. While existence of Nil is vital for List to work, no special structure of this kind is needed for arrays.
I've found a workaround for empty match check that might work in most cases:
collection.mutable.ArrayBuffer(2) match {
case collection.mutable.ArrayBuffer(v, _*) => v * 2
case _ => 0
}
I first check if array has at least one element and otherwise it should be empty.
I am mucking around with scala implementing some common algorithms. While attempting to recreate a bubble sort I ran into this issue
Here is an implementation of an the inner loop that bubbles the value to the top:
def pass(xs:List[Int]):List[Int] = xs match {
case Nil => Nil
case x::Nil => x::Nil
case l::r::xs if(l>r) => r::pass(l::xs)
case l::r::xs => l::pass(r::xs)
}
My issue is with case Nil => Nil. I understand that I need this is because I could apply Nil to this function. Is there a way to ensure that Nil can't be provided as an argument in a manner that would satisfy the compiler so I can eliminate this case?
List has two subtypes, Nil and ::, so :: represents a list that has at least one element.
def pass(xs: ::[Int]):List[Int] = xs match {
case x::Nil => x::Nil
case l::r::xs if(l>r) => r::pass(new ::(l,xs))
case l::r::xs => l::pass(new ::(r, xs))
}
In that case you can simply play with the case clauses order:
def pass(xs:List[Int]):List[Int] = xs match {
case l::r::xs if(l>r) => r::pass(l::xs)
case l::r::xs => l::pass(r::xs)
case xs => xs
}
The first two clauses will only match lists with one or more elements. The last clause will match elsewhere.
This would roughly correspond to a refinement of the original type, where you would write a type whose members were a subset of the initial type. You would then show that, for every input x to your function, that x was non Nil. As this requires a good amount of proof (you can implement this in Coq with dependent types using a subset type), the better thing to do in this situation might be to introduce a new type, which was a list having no Nil constructor, only a constructor for cons and a single element.
EDIT: As Scala allows you to use subtyping over the List type to enforce this, you can prove it in the type system decidably using that subtype. This is still a proof, in the sense that any type checking corresponds to a proof that the program does indeed inhabit some type, it's just something the compiler can prove completely.
PartialFunctions
In Scala, a PartialFunction is, in short, a function that additionally defines an isDefinedAt method.
It is easy to define partial functions with a series of case statement. A trivial example would be, e.g.:
scala> val pf: PartialFunction[Int, Unit] = {
| case 42 => ()
| }
pf: PartialFunction[Int,Unit] = <function1>
scala> pf.isDefinedAt(42)
res0: Boolean = true
scala> pf.isDefinedAt(0)
res1: Boolean = false
isDefinedAt is automatically generated from the list of cases defining the partial function.
Context
The Lift framework makes use of partial functions in many places, e.g. to define whether a request should be processed by Lift's engine or served directly from a file on disk, as is. and sometimes, I find myself wanting to write a case statement that matches all input parameters and only later decide if I want to return a value or not. This means that the initial series of cases is not enough any more to determine if my function is defined at a given value or not
For instance, in Lift, I want to add a rule that all html and htm files are served directly, and that files with the “lift” extension should be processed. It would look easy to do something like this:
LiftRules.liftRequest.prepend {
case Req(path, extension, tpe) => extension match {
case "html" | "htm" => false
case "lift" => true
}
}
Unfortunately, in this case, the compiler thinks that my partial function is defined everywhere, as the first case always matches. It's the nested match that may not match all incoming requests. And, is a request is not matched, a MatchError is thrown.
Question
Is there a simple way to make the compiler consider nested match statements when defining a partial function, or is the only way to do it to inline all nested conditionals like this?
LiftRules.liftRequest.prepend {
case Req(path, extension, tpe) if extension == "html" || extension == "htm" => false
case Req(path, extension, tpe) if extension == "lift" => true
}
In this example, it's largely doable, but the readability is decreased, and I've faced cases where inlining all checks looks very ugly.
In this case, you may want to write
LiftRules.liftRequest.prepend {
case Req(path, "html" | "htm", tpe) => false
case Req(path, "lift", tpe) => true
}
For more complicated cases, you’ll need to define your own extractor which you’ll have to use instead of a nested case statement.
object CheckExtension {
def unapply(ext: String) = ext match {
case "lift" => Some(true)
case "html" | "htm" => Some(false)
case _ => None
}
}
LiftRules.liftRequest.prepend {
case Req(path, CheckExtension(valid), tpe) => valid
}
This will only match if your predefined unapply function returns Some and assign the value of Some to the free variable valid. If unapply returns None, no match is being generated.