i have a question about disjoint Matching pattern. The matching pattern is disjoint when each case does not step on other cases.
def func(list: List[Int]): Int = list match {
case Nil => 0
case x::t if (x < func(t)) => x
case x::t => func(t)
}
My question: is "if" statement also counted to check if these cases disjoint is?
so if we have a patching pattern like this it means the last case also include the second case and it would not be disjoint anyway . But if i change the last case to
case x::t if (x >= func(t)) => func(t)
would the matching pattern considered disjoint ?
Since x < func(t) = !(x >= func(t)), yes, these patterns are all disjoint. The compiler doesn't use predicate disjointness in anyway; this will have no concrete implications.
Related
I'm reading some Scala problems and I see this:
def last[A](l: List[A]): A = l match {
case h :: Nil => h
case _ :: tail => last(tail)
case _ => throw new NoSuchElementException
}
I understand the basics of the cons operator. But where does the h come from?
In that top case h, I can see how we're saying in the event that there is Nil at the end of the list, return h, which would be the last element of the list. But where is h even defined?
The h is defined right there in the case statement.
Scala's pattern matching has pretty concise syntax that can take a beat to get used to. It mixes some stuff that look very similar:
If you include a literal value, the object you're matching on must be equal to that value. Example: case 1 :: tail => ... matches only lists that start with 1.
If you include an _, that matches anything. Example: case _ :: tail => ...
If you include a new variable name, that matches anything, and assigns what it matched to that variable within the scope of the corresponding body. Example: case h :: tail => ... which matches the exact same inputs as the previous example but also assigns the first element to h within the "..." section.
h is an identifier that represents a single element of type A and is defined in the case clause itself: the letter "h" is sensible in this context because it clearly means "head." However, you can use whatever legal Scala identifier you want:
def last[A](l: List[A]): A = l match {
case baconWrappedShrimp :: Nil => baconWrappedShrimp
case _ :: tail => last(tail)
case _ => throw new NoSuchElementException
}
Scala pattern matching allows you to write temp variables in the cases.
The first case covers the case where l is a the following list {h, Nil}. Pay attention that the '::' operator is used to concatanate a single element with a list. Unlike the ':::' operator which concatanates two lists.
So I read about right-associative operators like the cons operator in Scala. I'm wondering why they work in case statements. It seems like you can pattern match using the cons statement here?
def findKth1[A](k:Int, l:List[A]):A = (k, l) match {
case (0, h::_) => h
case(k, _::tail) if k > 0 => findKth1(k - 1, tail)
case _ => throw new NoSuchElementException
}
findKth1(2, List(3,4,5,6))
res1: Int = 5
What is the placeholder doing here? I've only seen placeholders used in functions like this: <SomeList>.map(_.doThing). Is it the same concept?
The only difference with :: and ::: is that ::: is used for 2 Lists right?
tl;dr It isn't pattern matching the operator, it's pattern matching a case class called ::
There are a couple of things happening at the same time. First of all, there may be a bit of confusion, because :: is a method on List:
val x: List[Int] = 1 :: 2 :: 3 :: Nil
But there is also a case class :: that, according to the docs is:
A non empty list characterized by a head and a tail.
More info here
Scala's case classes automatically come with extractor methods(unapply), which allow pattern matching, as in case User(name, age) => ....
You are also allowed to use the case class name in an infix position (although you shouldn't do so, except when the case class is used like an operator, such as in this case). So case head :: tail => ... is the same as case ::(head, tail) => .... More info here
When pattern matching, you can use _ to mean that there will be a value there, but you don't care about it, so you aren't providing it a name.
So the three cases you provided are roughly:
A tuple where the first value is 0, and the second value is a list with a head to be called h, and a tail which we will ignore.
A tuple with some integer to be called k, and a list with a head that we don't care about, and a tail, which we will call tail. Also, k must be greater than 0
Anything else, then throw a NoSuchElementException
Let's say, I have the following code snippet:
val num = Future.successful(10)
num map {
case n if n > 0 => // do something
case _ // do something
}
My question is: can I simplify case n if n > 0 somehow?
I expected that I can write something like:
case _ > 0 => // do something
or with explicitly specified type (although we know that Future has inferred type [Int]):
case _: Int > 0 => // do something
Can this code be simplified somehow?
You can't simplify case n if n > 0 => ....
Every case clause in a pattern match needs to have a pattern and (optionally) a guard.
The syntax you are referring to (_ > 0) is only valid in lambdas, but there's no similar special syntax for case clauses.
If you want to simplify the guard, you can filter the Future a priori:
val num = Future.successful(10).filter(_ > 0).map { nat =>
}
Otherwise, you can keep the guard and use Future.collect:
val num = Future.successful(10).collect {
case n if n > 0 => // do something
}
One important thing to note is that if the partial function is not defined for the value which returned (i.e for your case -1) then the resulting future will be a Failure containing a NoSuchElementException.
Other than these options, you'll need the guard. I don't see any syntactically shorter way to express it.
I am trying to understand this piece of code here
def countChange(money: Int, coins: List[Int]): Int = (money, coins) match {
case (0, _) => 1
case (m, _) if m < 0 => 0
case (_, cs) if cs.isEmpty => 0
case (m, cs) => countChange(m - cs.head, cs) + countChange(m, cs.tail)
}
}
where I cannot understand the pairs (0,_), (m,_), (_,cs) and (m,cs) because the terms m and cs are undefined in the body of the code.
What is this construction in traversing the List called? A pair of some matching patterns?
The list is being traversed recursively. This construct is called pattern matching
You can read it like:
If the tuple (money, coins) is a tuple whose first value is 0 then return 1 ignore the second value of the tuple
If the tuple (money, coins) is a tuple has a first value below 0 then return 0 ignore the second value of the tuple.
And so on...
The _ is used in pattern matching to simbolize that we don't care what that parameter is, it can be anything
Pattern matching in Scala is backed by the unapply method of Objects, read more about extractors. Meaning that for each case the method unapply will be called with the tuple (money, coins) as argument and if determines that it is a match it will pass the respective first value and second value to the case clauses.
Example:
The statement case (m, _) => ... will lead to the call Tuple2.unapply((money, coins))
Note
Case classes already define unapply methods for us. That's why you can use them in pattern matching 'out of the box'. Tuple2 is a case class.
This is an example of pattern matching, which is being used to recursively traverse your list of coins. Here is the same code re-written with comments, the important thing to know is that each case statement is matching a possible pattern of the tuple, and the _ are used for ignoring pieces of the tuple.
def countChange(money: Int, coins: List[Int]): Int = {
// Construct a tuple for pattern matching on
val tuple: (Int, List[Int]) = (money, coins)
tuple match {
// Check to see if money == 0
case (0, _) => 1
// m represents money, use a guard to check if m is negative
case (m, _) if m < 0 => 0
// cs represents coins, use a guard statement check for empty list
case (_, cs) if cs.isEmpty => 0
// Recursive step. Since the patterns are tried in order, we
// now know that if we make it to here m (money) is non-zero
// and non-negative, and we know that cs (coins) is a non-empty
// list. Now we can call the recursive function safely on
// the head of the list
case (m, cs) => countChange(m - cs.head, cs) + countChange(m, cs.tail)
}
}
This construct is often used to match on more than one variable at the same time. At the top of the match, you see (money, coins). This means that it's matching on the pair of both money and coins. It doesn't have a name, because it's perfectly ordinary matching on two values simultaneously.
I cannot understand the pairs (0,_), (m,_), (_,cs) and (m,cs) because the terms m and cs are undefined in the body of the code.
These terms are defined in the code. The cases define them. That's what matching and destructuring is all about.
(money, coins) match {
case (0, _) => 1 // If money == 0, then coins is ignored and we return 1
case (m, _) if m < 0 => 0 // m = money, coins is ignored. If m < 0, return 0
case (_, cs) if cs.isEmpty => 0 // money is ignored, cs = coins.
// If we have no coins, return 0.
case (m, cs) => countChange(m - cs.head, cs) + countChange(m, cs.tail)
// Otherwise, m = money, cs = coins. Recurse down the list with
// countChange(money - coins.head, coins) + countChange(money, coins.tail)
}
The reason for the tupling (money, coins) is because these patterns depend on both money and coins. You'd either need to nest matchs (ugly) or do even more ugly boolean logic in order to replicate these semantics.
I have the following code for sorting arrays which I want to verify in Stainless (previously known as Leon):
import stainless.lang._
import stainless.collection._
object QuickSort {
def isSorted(list: List[BigInt]): Boolean = list match {
case Cons(x, xs # Cons(y, _)) => x <= y && isSorted(xs)
case _ => true
}
def quickSort(list: List[BigInt]): List[BigInt] = (list match {
case Nil() => Nil[BigInt]()
case Cons(x, xs) => par(x, Nil(), Nil(), xs)
}) ensuring { res => isSorted(res) }
def par(x: BigInt, l: List[BigInt], r: List[BigInt], ls: List[BigInt]): List[BigInt] = {
require(l.forall(_ <= x) && r.forall(_ >= x))
ls match {
case Nil() => quickSort(l) ++ Cons(x, quickSort(r))
case Cons(x2, xs2) => if (x2 <= x) par(x, Cons(x2, l), r, xs2) else par(x, l, Cons(x2, r), xs2)
}
} ensuring {res => isSorted(res)}
}
I have plenty of directions to go from here (as it doesn't succeed to verify) however it seems to me that the verification should succeed with the hints provided and I want to know why it doesn't. I explain myself:
Apparently for verifying par function I need to proof that the two cases imply the isSorted postcondition separately. Now as the second case contains a recursive call then is evident that it implies the postcondition. For the first case of par, we have that the left and right subarrays are sorted and the precondition tells me that all the elements are sorted with respect to the pivot.
This last bit should imply in my opinion that the concatenating list is sorted as well. So why does it not verify? How could instruct Stainless to verify it? Do I need to add hints on the length and size to facilitate the task to Stainless?
Edit:
def concatIsSorted(l1 : List[BigInt],l2 : List[BigInt],pivot : BigInt) : Boolean = {
require(isSorted(l1) && isSorted(l2) && l1.forall(_ <= pivot) && l2.forall(_ >= pivot))
isSorted(l1 ++ Cons(pivot,l2)) because{
l1 match{
case Nil() => isSorted(Cons(pivot,l2))
case Cons(h,Nil()) => h <= pivot && isSorted(Cons(pivot,l2))
case Cons(h,t) => h <= t.head && concatIsSorted(t,l2,pivot)
}
}
}.holds
Since this is looks like a homework question, I will try to guide you towards the solution without giving it away.
First note that the program verifies if you replace the Nil() case in par with case Nil() => Nil(). This shows that the verifier is not able to prove that the result of quickSort(l) ++ Cons(x, quickSort(r)) is sorted (but it manage to do it for Nil()!).
When --debug=verification is not sufficient to understand why the verifier is not able to prove you think it should, the way to proceed is to introduce extra functions where you can precisely state your expectations. For instance if you define:
def plusplus(l: List[BigInt], r: List[BigInt]): List[BigInt] = l ++ r
And annotate it with your what you expect the verifier to prove, that is
Assuming l and r sorted and l < r (for the appropriate definition of <)
The result of l ++ r is sorted
You will see that the verifier is not able to prove this property, meaning you need to guide the verification further with addition addition auxiliary functions, pre and postcondition.
Note that this example is taken from Dependent Types for Program Termination Verification, reading the paper might help you here.