I have the following abstract class with the method :: and the inner class ListNode
abstract class SimpleList[+Elem] {
def head: Elem
def tail: SimpleList[Elem]
def isEmpty: Boolean
def ::[NewElem >: Elem] (newHead: NewElem): SimpleList[NewElem] = new ListNode(hd= newHead, tl= this)
private class ListNode[Elem](hd: Elem, tl: SimpleList[Elem]) extends SimpleList[Elem] {
override def head = hd
override def tail = tl
override def isEmpty = false
object SimpleList {
def main(args: Array[String]): Unit = {
val squareNumbers = 1 :: 4 :: 9 :: 16 :: Empty
}
}
The :: method uses 'this' to define a new ListNode.
As you can see in the main method, the :: method is invoked.
It seems like it creates a new ListNode from 1 and 4 etc.
However I dont understand what the 'this' keyword refernces in this case.
Does it reference the 4?
And what is a SimpleList in this defintion?
A custom data structure?
You have two questions and that is what is causing you confusion. The first thing is what does this means, well it means this object, the current instance where the method was called. Which makes sense, since prepending an element to a List is just create a new one where the passed element is the head and the current one is the tail.
Now the second question is how that works in the main, differently to most methods :: is called on the right-hand side and the argument passed is the left-hand side (this is specified on the language specs, every method that ends with colons : will behave like that).
So you have to see the code like this:
// The operations are applied in this order
1 :: (2 :: (3 :: (4 :: Empty)))
// And thus it is the same as
Empty.::(4).::(3).::(2).::(1)
// Which is easier to see like this
val res0 = Empty // Empty
val res1 = res0.::(4) // 4 :: Empty - (head = 4, tail / this = res0)
val res2 = res1.::(3) // 3 :: (4 :: Empty) - (head = 3, tail / this = res1)
val res3 = res2.::(2) // 2 :: (3 :: (4 :: Empty)) - (head = 2, tail / this = res2)
val res4 = res3.::(1) // 1 :: (2 :: (3 :: (4 :: Empty))) - (head = 1, tail / this = res3)
So you can see that when we create the final List we are creating the List whose head is 1 and its tail was 2 :: 3 :: 4 :: Empty because we called the :: method on that previous List.
For your final question, yes CustomList is a custom data structure, an abstract class, a new type, etc.
You should already understand that if you want to continue with more complex topics.
Related
I have a polymorphic function which can turn lists into sets:
import shapeless.PolyDefns.~>
import shapeless._
val lists = List(1,2) :: List("A", "B") :: List(1.1, 2.2) :: HNil
object sss extends (List ~> Set) {
def apply[T](l:List[T]):Set[T] = {
l.toSet
}
}
lists.map(sss) // I want: Set(1,2) :: Set("A", "B") :: Set(1.1, 2.2) :: HNil
But what if I want to change the behavior of this function - I now want to add an extra argument which will specify which item in the input list should be put into the set. Here's an incorrect syntax - can you show me the correct way to do it?
object sss extends (List ~> Set) { // Compiler says no!
def apply[T](i:Int)(l:List[T]):Set[T] = {
l.slice(i,i+1).toSet
}
}
I think this is failing because the additional argument makes it no longer fit the signature of List ~> Set, so how can I overcome this?
There are a couple of workarounds for parametrizing a Poly, one of which is mentioned in the other answer, although the exact implementation there won't work. Instead you need to do this:
import shapeless._, shapeless.poly.~>
val lists = List(1, 2) :: List("A", "B") :: List(1.1, 2.2) :: HNil
class sss(i: Int) extends (List ~> Set) {
def apply[T](l: List[T]): Set[T] = l.slice(i, i+1).toSet
}
object sss1 extends sss(1)
lists.map(sss1)
…where the fact that sss1 is defined as an object (not a val) is necessary for the last line to compile.
That approach compiles, but it's not possible to use it in lots of contexts—e.g. you can't define your sss1 (or whatever) object in a method where the type of the hlist is generic.
Here's a slightly messier but more flexible workaround I've used before:
import shapeless._
val lists = List(1, 2) :: List("A", "B") :: List(1.1, 2.2) :: HNil
object sss extends Poly2 {
implicit def withI[T]: Case.Aux[List[T], Int, Set[T]] =
at((l, i) => l.slice(i, i + 1).toSet)
}
lists.zipWith(lists.mapConst(1))(sss)
// Set(2) :: Set(B) :: Set(2.2) :: HNil
Now you could actually write a method that took a generic L <: HList and the slice parameter i—you'd just need several implicit arguments to support the mapConst and zipWith applications.
Neither approach is very elegant, though, and I personally tend to avoid Poly most of the time—defining a custom type class is almost going to be cleaner, and in many cases required.
As you already pointed out, you cannot change the signature of the polymorphic function. But could create your function dynamically:
class sss(i: Int) extends (List ~> Set) {
def apply[T](l:List[T]): Set[T] = {
l.slice(i, i+1).toSet
}
}
val sss1 = new sss(1)
lists.map(sss1) // Set(2) :: Set(B) :: Set(2.2) :: HNil
I'm using Shapeless 2.0 and I'm trying to use HList to validate input — with as much of the checking as possible performed at compile time.
I have an HList spec that specifies what type of input I'm expecting (the types should be checked at compile time) and may also include a runtime check to be performed (e.g., to test if a number is even or odd).
Consider the following specification:
trait Pred[T] { def apply(t: T): Boolean }
val IsString = new Pred[String] { def apply(s: String) = true }
val IsOddNumber = new Pred[Int] { def apply(n: Int) = n % 2 != 0 }
val IsEvenNumber = new Pred[Int] { def apply(n: Int) = n % 2 == 0 }
val spec = IsEvenNumber :: IsString :: IsString :: IsOddNumber :: HNil
And various sample inputs:
val goodInput = 4 :: "foo" :: "" :: 5 :: HNil
val badInput = 4 :: "foo" :: "" :: 4 :: HNil
val malformedInput = 4 :: 5 :: "" :: 6 :: HNil
How would I make a function where I can effectively do:
input.zip(spec).forall{case (input, test) => test(input)}
So the following would happen:
f(spec, goodInput) // true
f(spec, badInput) // false
f(spec, malformedInput) // Does not compile
These answers by Travis Brown include most of what's needed:
https://stackoverflow.com/a/20452151/86485
https://stackoverflow.com/a/21005225/86485
but it took me a long time to find those answers, figure out that they were applicable to your problem, and work out the details of combining and applying them.
And I think your question adds value because it demonstrates how this can come up when solving a practical problem, namely validating input. I'll also try to add value below by showing a complete solution including demo code and tests.
Here's generic code for doing the checking:
object Checker {
import shapeless._, poly._, ops.hlist._
object check extends Poly1 {
implicit def apply[T] = at[(T, Pred[T])]{
case (t, pred) => pred(t)
}
}
def apply[L1 <: HList, L2 <: HList, N <: Nat, Z <: HList, M <: HList](input: L1, spec: L2)(
implicit zipper: Zip.Aux[L1 :: L2 :: HNil, Z],
mapper: Mapper.Aux[check.type, Z, M],
length1: Length.Aux[L1, N],
length2: Length.Aux[L2, N],
toList: ToList[M, Boolean]) =
input.zip(spec)
.map(check)
.toList
.forall(Predef.identity)
}
And here's the demo usage code:
object Frank {
import shapeless._, nat._
def main(args: Array[String]) {
val IsString = new Pred[String] { def apply(s: String) = true }
val IsOddNumber = new Pred[Int] { def apply(n: Int) = n % 2 != 0 }
val IsEvenNumber = new Pred[Int] { def apply(n: Int) = n % 2 == 0 }
val spec = IsEvenNumber :: IsString :: IsString :: IsOddNumber :: HNil
val goodInput = 4 :: "foo" :: "" :: 5 :: HNil
val badInput = 4 :: "foo" :: "" :: 4 :: HNil
val malformedInput1 = 4 :: 5 :: "" :: 6 :: HNil
val malformedInput2 = 4 :: "foo" :: "" :: HNil
val malformedInput3 = 4 :: "foo" :: "" :: 5 :: 6 :: HNil
println(Checker(goodInput, spec))
println(Checker(badInput, spec))
import shapeless.test.illTyped
illTyped("Checker(malformedInput1, spec)")
illTyped("Checker(malformedInput2, spec)")
illTyped("Checker(malformedInput3, spec)")
}
}
/*
results when run:
[info] Running Frank
true
false
*/
Note the use of illTyped to verify that code that should not compile, does not.
Some side notes:
I initially went down a long garden path with this, where I thought it would be important for the polymorphic function check to have a more specific type than Poly1, to represent that the return type in all cases is Boolean. So I kept trying to make it work with extends (Id ~>> Boolean). But it turns out not to matter whether the type system knows that the result type is the Boolean in every case. It's enough that the only case that we actually have has the right type. extends Poly1 is a marvelous thing.
Value-level zip traditionally allows unequal lengths and discards the extras. Miles followed suit in Shapeless's type-level zip, so we need a separate check for equal lengths.
It's a bit sad that the call site has to import nat._, otherwise the implicit instances for Length aren't found. One would prefer these details to be handled at the definition site. (A fix is pending.)
If I understand correctly, I can't use Mapped (a la https://stackoverflow.com/a/21005225/86485) to avoid the length check, because some of my checkers (e.g. IsString) have singleton types that are more specific than just e.g. Pred[String].
Travis points out that Pred could extend T => Boolean, making it possible to use ZipApply. I leave following this suggestion as an exercise for the reader :-)
Say I've got a function taking one argument
def fun(x: Int) = x
Based on that, I want to generate a new function with the same calling convention, but that'll apply some transformation to its arguments before delegating to the original function. For that, I could
def wrap_fun(f: (Int) => Int) = (x: Int) => f(x * 2)
wrap_fun(fun)(2) // 4
How might one go about doing the same thing, except to functions of any arity that only have the part of the arguments to apply the transformation to in common?
def fun1(x: Int, y: Int) = x
def fun2(x: Int, foo: Map[Int,Str], bar: Seq[Seq[Int]]) = x
wrap_fun(fun1)(2, 4) // 4
wrap_fun(fun2)(2, Map(), Seq()) // 4
How would a wrap_fun definition making the above invocations work look like?
This can be done in fairly straightforwardly using shapeless's facilities for abstracting over function arity,
import shapeless._
import HList._
import Functions._
def wrap_fun[F, T <: HList, R](f : F)
(implicit
hl : FnHListerAux[F, (Int :: T) => R],
unhl : FnUnHListerAux[(Int :: T) => R, F]) =
((x : Int :: T) => f.hlisted(x.head*2 :: x.tail)).unhlisted
val f1 = wrap_fun(fun _)
val f2 = wrap_fun(fun1 _)
val f3 = wrap_fun(fun2 _)
Sample REPL session,
scala> f1(2)
res0: Int = 4
scala> f2(2, 4)
res1: Int = 4
scala> f3(2, Map(), Seq())
res2: Int = 4
Note that you can't apply the wrapped function immediately (as in the question) rather than via an assigned val (as I've done above) because the explicit argument list of the wrapped function will be confused with the implicit argument list of wrap_fun. The closest we can get to the form in the question is to explicitly name the apply method as below,
scala> wrap_fun(fun _).apply(2)
res3: Int = 4
scala> wrap_fun(fun1 _).apply(2, 4)
res4: Int = 4
scala> wrap_fun(fun2 _).apply(2, Map(), Seq())
res5: Int = 4
Here the explicit mention of apply syntactically marks off the first application (of wrap_fun along with its implicit argument list) from the second application (of the transformed function with its explicit argument list).
As usual in Scala, there's yet another way to achieve what you want to do.
Here is a take based on currying of the first argument together with the compose of Function1:
def fun1(x : Int)(y : Int) = x
def fun2(x : Int)(foo : Map[Int, String], bar : Seq[Seq[Int]]) = x
def modify(x : Int) = 2*x
The resulting types as REPL shows you will be:
fun1: (x: Int)(y: Int)Int
fun2: (x: Int)(foo: Map[Int,String], bar: Seq[Seq[Int]])Int
modify: (x: Int)Int
And instead of wrapping the functions fun1 and fun2, you compose them, as technically, they are now both Function1 objects. This allows you to make calls like the following:
(fun1 _ compose modify)(2)(5)
(fun2 _ compose modify)(2)(Map(), Seq())
Both of which will return 4. Granted, the syntax is not that nice, given that you have to add the _ to distinguish fun1's application from the function object itself (on which you want to call the compose method in this case).
So Luigi's argument that it is impossible in general remains valid, but if you are free to curry your functions you can do it in this nice way.
Since functions taking different numbers of arguments are different, unrelated types, you cannot do this generically. trait Function1 [-T1, +R] extends AnyRef and nothing else. You will need a separate method for each arity.
While I voted for and agree with Luigi's answer–because, you know... he's right; Scala doesn't have direct, in-built support for such a thing–it's worth noting that what you're trying to do isn't impossible; it's just that it's a bit of a pain to pull off, and, often times, you're best off just implementing a separate method per desired arity.
That said, though... we can actually do this HLists. If you're interested in trying it out, naturally, you'll need to obtain an HList implementation. I recommend utilizing Miles Sabin's excellent shapeless project and its implementation of HLists. Anyway, here's an example of its use that accomplishes something akin to what you seem to be looking for:
import shapeless._
trait WrapperFunner[T] {
type Inputs <: HList
def wrapFun(inputs: Inputs) : T
}
class WrapsOne extends WrapperFunner[Int] {
type Inputs = Int :: HNil
def wrapFun(inputs: Inputs) : Int = {
inputs match {
case num :: HNil => num * 2
}
}
}
class WrapsThree extends WrapperFunner[String] {
type Inputs = Int :: Int :: String :: HNil
def wrapFun(inputs: Inputs) : String = {
inputs match {
case firstNum :: secondNum :: str :: HNil => str + (firstNum - secondNum)
}
}
}
object MyApp extends App {
val wo = new WrapsOne
println(wo.wrapFun(1 :: HNil))
println(wo.wrapFun(17 :: HNil))
//println(wo.wrapFun(18 :: 13 :: HNil)) // Would give type error
val wt = new WrapsThree
println(wt.wrapFun(5 :: 1 :: "your result is: " :: HNil))
val (first, second) = (60, 50)
println(wt.wrapFun(first :: second :: "%s minus %s is: ".format(first, second) :: HNil))
//println(wt.wrapFun(1 :: HNil)) // Would give type error
}
Running MyApp results in:
2
34
your result is: 4
60 minus 50 is: 10
Or, extended closer to your particular case:
import shapeless._
trait WrapperFunner[T] {
type Inputs <: HList
def wrapFun(inputs: Inputs) : T
}
trait WrapperFunnerBase extends WrapperFunner[Int] {
// Does not override `Inputs`
def wrapFun(inputs: Inputs) : Int = {
inputs match {
case (num: Int) :: remainder => num
}
}
}
class IgnoresNothing extends WrapperFunnerBase {
type Inputs = Int :: HNil
}
class IgnoresLastTwo extends WrapperFunnerBase {
type Inputs = Int :: Int :: String :: HNil
}
object MyApp extends App {
val in = new IgnoresNothing
println(in.wrapFun(1 :: HNil))
println(in.wrapFun(2 :: HNil))
//println(in.wrapFun(3 :: 4 :: HNil)) // Would give type error
val ilt = new IgnoresLastTwo
println(ilt.wrapFun(60 :: 13 :: "stupid string" :: HNil))
println(ilt.wrapFun(43 :: 7 :: "man, that string was stupid..." :: HNil))
//println(ilt.wrapFun(1 :: HNil)) // Would give type error
}
results in:
1
2
60
43
I'm working through the scala labs stuff and I'm building out a function that will, in the end, return something like this:
tails(List(1,2,3,4)) = List(List(1,2,3,4), List(2,3,4), List(3,4), List(4), List())
I got this working by using two functions and using some recursion on the second one.
def tails[T](l: List[T]): List[List[T]] = {
if ( l.length > 1 )trailUtil(List() ::: List(l))
else List() ::: List(l);
}
def trailUtil[T](l:List[List[T]]) : List[List[T]] = {
if ( l.last.length == 0)l
else trailUtil(l :+ l.last.init);
}
This is all good a great but it's bugging me that I need two functions to do this. I tried switching: trailUtil(List() ::: List(l)) for an anonymous function but I got this error type mismatch; found :List[List[T]] required:Int from the IDE.
val ret : List[List[T]] = (ll:List[List[T]]) => {
if ( ll.last.length == 0) ll else ret(ll :+ ll.last.init)
}
ret(List() ::: List(1))
Could someone please point me to what I am doing wrong, or a better way of doing this that would be great.
(I did look at this SO post but the different type are just not working for me):
What about this:
def tails[T](l: List[T]): List[List[T]] =
l match {
case h :: tail => l :: tails(tail)
case Nil => List(Nil)
}
And a little bit less idiomatic version:
def tails[T](input: List[T]): List[List[T]] =
if(input.isEmpty)
List(List())
else
input :: tails(input.tail)
BTW try to avoid List.length, it runs in O(n) time.
UPDATE: as suggested by tenshi, tail-recursive solution:
#tailrec def tails[T](l: List[T], init: List[List[T]] = Nil): List[List[T]] =
l match {
case h :: tail => tails(tail, l :: init)
case Nil => init
}
You actually can define def inside another def. It allows to define function that actually has name which can be referenced and used for recursion. Here is how tails can be implemented:
def tails[T](l: List[T]) = {
#annotation.tailrec
def ret(ll: List[List[T]]): List[List[T]] =
if (ll.last.isEmpty) ll
else ret(ll :+ ll.last.tail)
ret(l :: Nil)
}
This implementation is also tail-recursive. I added #annotation.tailrec annotation in order to ensure that it really is (code will not compile if it's not).
You can also use build-in function tails (see ScalaDoc):
List(1,2,3,4).tails.toList
tails returns Iterator, so you need to convert it to list (like I did), if you want it. Also result will contain one extra empty in the end (in my example result would be List(List(1, 2, 3, 4), List(2, 3, 4), List(3, 4), List(4), List())), so you need deal with it.
What you are doing wrong is this:
val ret : List[List[T]]
So ret is a list of list of T. Then you do this:
ret(ll :+ ll.last.init)
That mean you are calling the method apply on a list of list of T. The apply method for lists take an Int parameter, and returns an element with that index. For example:
scala> List("first", "second", "third")(2)
res0: java.lang.String = third
I assume you wanted to write val ret: List[List[T]] => List[List[T]], that is, a function that takes a List[List[T]] and returns a List[List[T]]. You'd have other problems then, because val is referring to itself in its definition. To get around that, you could replace it with a lazy val:
def tails[T](l: List[T]): List[List[T]] = {
lazy val ret : List[List[T]] => List[List[T]] = { (ll:List[List[T]]) =>
if ( ll.last.length == 0) ll
else ret(ll :+ ll.last.init)
}
if ( l.length > 1 )ret(List() ::: List(l))
else List() ::: List(l);
}
But, of course, the easy solution is to put one def inside the other, like tenshi suggested.
You can also use folding:
val l = List(1,2,3,4)
l.foldLeft(List[List[Int]](l))( (outerList,element) => {
println(outerList)
outerList.head.tail :: outerList
})
The first parameter list is your start value/accumulator. The second function is the modifier. Typically, it modifies the start value, which is then passed to every element in the list. I included a println so you can see the accumulator as the list is iterated over.
I am trying to understand the Scala quicksort example from Wikipedia. How could the sample be disassembled step by step and what does all the syntactic sugar involved mean?
def qsort: List[Int] => List[Int] = {
case Nil => Nil
case pivot :: tail =>
val (smaller, rest) = tail.partition(_ < pivot)
qsort(smaller) ::: pivot :: qsort(rest)
}
As much as I can gather at this stage qsort is a function that takes no parameters and returns a new Function1[List[Int],List[Int]] that implements quicksort through usage of pattern matching, list manipulation and recursive calls. But I can't quite figure out where the pivot comes from, and how exactly the pattern matching syntax works in this case.
UPDATE:
Thanks everyone for the great explanations!
I just wanted to share another example of quicksort implementation which I have discovered in the Scala by Example by Martin Odersky. Although based around arrays instead of lists and less of a show-off in terms of varios Scala features I personally find it much less convoluted than its Wikipedia counterpart, and just so much more clear and to the point expression of the underlying algorithm:
def sort(xs: Array[Int]): Array[Int] = {
if (xs.length <= 1) xs
else {
val pivot = xs(xs.length / 2)
Array.concat(
sort(xs filter (pivot >)),
xs filter (pivot ==),
sort(xs filter (pivot <)))
}
}
def qsort: List[Int] => List[Int] = {
case Nil => Nil
case pivot :: tail =>
val (smaller, rest) = tail.partition(_ < pivot)
qsort(smaller) ::: pivot :: qsort(rest)
}
let's pick apart a few bits.
Naming
Operators (such as * or +) are valid candidates for method and class names in Scala (hence you can have a class called :: (or a method called :: for that matter - and indeed both exist). Scala appears to have operator-overloading but in fact it does not: it's merely that you can declare a method with the same name.
Pattern Matching
target match {
case p1 =>
case p2 =>
}
Where p1 and p2 are patterns. There are many valid patterns (you can match against Strings, types, particular instances etc). You can also match against something called an extractor. An extractor basically extracts arguments for you in the case of a match, so:
target match {
case MyExtractor(arg1, arg2, arg3) => //I can now use arg1, arg2 etc
}
In scala, if an extractor (of which a case class is an example) exists called X, then the pattern X(a, b) is equivalent to a X b. The case class :: has a constructor taking 2 arguments and putting this together we get that:
case x :: xs =>
case ::(x, xs) =>
Are equivalent. This match says "if my List is an instance of :: extract the value head into x and tail into xs". pattern-matching is also used in variable declaration. For example, if p is a pattern, this is valid:
val p = expression
This why we can declare variables like:
val x :: xs = List(1, 2, 3)
val (a, b) = xs.partition(_ % 2 == 0 ) //returns a Tuple2 which is a pattern (t1, t2)
Anonymous Functions
Secondly we have a function "literal". tail is an instance of List which has a method called partition which takes a predicate and returns two lists; one of those entries satisfying the predicate and one of those entries which did not.
val pred = (el: Int) => e < 2
Declares a function predicate which takes an Int and returns true iff the int value is less than 2. There is a shorthand for writing functions inline
tail.partition(_ < pivot) // _ is a placeholder for the parameter
tail.partition( (e: Int) => e < pivot )
These two expressions mean the same thing.
Lists
A List is a sealed abstract class with only two implementations, Nil (the empty list) and :: (also called cons), which is a non-empty list consisting of a head and a tail (which is also a list). You can now see that the pattern match is a match on whether the list is empty or not. a List can be created by cons-ing it to other lists:
val l = 1 :: 2 :: Nil
val m = List(1, 2, 3) ::: List(4, 5, 6)
The above lines are simply method calls (:: is a valid method name in scala). The only difference between these and normal method calls is that, if a method end in a colon : and is called with spaces, the order of target and parameter is reversed:
a :: b === b.::(a)
Function Types
val f: A => B
the previous line types the reference f as a function which takes an A and returns a B, so I could then do:
val a = new A
val b: B = f(a)
Hence you can see that def qsort: List[Int] => List[Int] declares a method called qsort which returns a function taking a List[Int] and returning a List[Int]. So I could obviously do:
val l = List(2, 4, 1)
val m = qsort.apply(l) //apply is to Function what run is to Runnable
val n = qsort(l) //syntactic sugar - you don't have to define apply explicitly!
Recursion
When a method call is tail recursive, Scala will optimize this into the iterator pattern. There was a msitake in my original answer because the qsort above is not tail-recursive (the tail-call is the cons operator)
def qsort: List[Int] => List[Int] = {
case Nil => Nil
case pivot :: tail =>
val (smaller, rest) = tail.partition(_ < pivot)
qsort(smaller) ::: pivot :: qsort(rest)
}
Let's rewrite that. First, replace the function literal with an instance of Function1:
def qsort: List[Int] => List[Int] = new Function1[List[Int], List[Int]] {
def apply(input: List[Int]): List[Int] = input match {
case Nil => Nil
case pivot :: tail =>
val (smaller, rest) = tail.partition(_ < pivot)
qsort(smaller) ::: pivot :: qsort(rest)
}
}
Next, I'm going to replace the pattern match with equivalent if/else statements. Note that they are equivalent, not the same. The bytecode for pattern matches are more optimized. For instance, the second if and the exception throwing below do not exist, because the compile knows the second match will always happen if the first fails.
def qsort: List[Int] => List[Int] = new Function1[List[Int], List[Int]] {
def apply(input: List[Int]): List[Int] = if (input == Nil) {
Nil
} else if (input.isInstanceOf[::[_]] &&
scala.collection.immutable.::.unapply(input.asInstanceOf[::[Int]]) != None) {
val unapplyResult = scala.collection.immutable.::.unapply(input.asInstanceOf[::[Int]]).get
val pivot = unapplyResult._1
val tail = unapplyResult._2
val (smaller, rest) = tail.partition(_ < pivot)
qsort(smaller) ::: pivot :: qsort(rest)
} else {
throw new scala.MatchError(input)
}
}
Actually, val (smaller, rest) is pattern match as well, so Let's decompose it as well:
def qsort: List[Int] => List[Int] = new Function1[List[Int], List[Int]] {
def apply(input: List[Int]): List[Int] = if (input == Nil) {
Nil
} else if (input.isInstanceOf[::[_]] &&
scala.collection.immutable.::.unapply(input.asInstanceOf[::[Int]]) != None) {
val unapplyResult0 = scala.collection.immutable.::.unapply(input.asInstanceOf[::[Int]]).get
val pivot = unapplyResult0._1
val tail = unapplyResult0._2
val tmp0 = tail.partition(_ < pivot)
if (Tuple2.unapply(tmp0) == None)
throw new scala.MatchError(tmp0)
val unapplyResult1 = Tuple2.unapply(tmp0).get
val smaller = unapplyResult1._1
val rest = unapplyResult1._2
qsort(smaller) ::: pivot :: qsort(rest)
} else {
throw new scala.MatchError(input)
}
}
Obviously, this is highly unoptmized. Even worse, there are some function calls being done more than once, which doesn't happen in the original. Unfortunately, to fix that would require some structural changes to the code.
There's still some syntactic sugar here. There is an anonymous function being passed to partition, and there is the syntactic sugar for calling functions. Rewriting those yields the following:
def qsort: List[Int] => List[Int] = new Function1[List[Int], List[Int]] {
def apply(input: List[Int]): List[Int] = if (input == Nil) {
Nil
} else if (input.isInstanceOf[::[_]] &&
scala.collection.immutable.::.unapply(input.asInstanceOf[::[Int]]) != None) {
val unapplyResult0 = scala.collection.immutable.::.unapply(input.asInstanceOf[::[Int]]).get
val pivot = unapplyResult0._1
val tail = unapplyResult0._2
val func0 = new Function1[Int, Boolean] {
def apply(input: Int): Boolean = input < pivot
}
val tmp0 = tail.partition(func0)
if (Tuple2.unapply(tmp0) == None)
throw new scala.MatchError(tmp0)
val unapplyResult1 = Tuple2.unapply(tmp0).get
val smaller = unapplyResult1._1
val rest = unapplyResult1._2
qsort.apply(smaller) ::: pivot :: qsort.apply(rest)
} else {
throw new scala.MatchError(input)
}
}
For once, the extensive explanations about each syntactic sugar and how it works are being done by others. :-) I hope this complements their answers. Just as a final note, the following two lines are equivalent:
qsort(smaller) ::: pivot :: qsort(rest)
qsort(rest).::(pivot).:::(qsort(smaller))
The pivot in this pattern matching example is the first element of the list:
scala> List(1,2,3) match {
| case x :: xs => println(x)
| case _ => println("empty")
| }
1
The pattern matching is based on extractors and the cons is not part of the language. It uses the infix syntax. You can also write
scala> List(1,2,3) match {
| case ::(x,xs) => println(x)
| case _ => println("empty")
| }
1
as well. So there is a type :: that looks like the cons operator. This type defines how it is extracted:
final case class ::[B](private var hd: B, private[scala] var tl: List[B]){ ... }
It's a case class so the extractor will be generated by the Scala compiler. Like in this example class A.
case class A(x : Int, y : Int)
A(1,2) match { case x A y => printf("%s %s", x, y)}
-> 1 2
Based on this machinary patterns matching is supported for Lists, Regexp and XML.