synapse
synapse

Reputation: 5728

Currying by second argument

I need to implement quicksort with several ways to select pivot, so I've implemented a routine that takes a pivot chooser as a parameter. But definitions of concrete implementations contain lots of boilerplate, is there a more concise way to define them?

  private def qsort[a <% Ordered[a]](xs: Stream[a])(choosePivot:Stream[a] => a): Stream[a] = {
    if(xs.lengthCompare(1) <= 0) xs
    else {
      val pivot = choosePivot(xs)
      val l = xs.filter(_ < pivot)
      val r = xs.filter(_ > pivot)
      qsort(l)(choosePivot) ++ pivot#::qsort(r)(choosePivot)
    }
  }

  def qsortHead[a <% Ordered[a]](xs: Stream[a]) = qsort(xs)(ys => ys.head)

  def qsortLast[a <% Ordered[a]](xs: Stream[a]) = qsort(xs)(ys => ys.last)

  def qsortRandom[a <% Ordered[a]](xs: Stream[a]) = qsort(xs)(ys => ys(rng.nextInt(ys.length)))

In Haskell I could just write something like qsortHead = qsort head if the choose pivot function is the first parameter or qsortHead xs = qsort xs (\ys -> head ys) if it's the second. Is there something similar in Scala?

Upvotes: 2

Views: 163

Answers (2)

DaoWen
DaoWen

Reputation: 33019

I want to point out that Ordered has been mostly phased out of the Scala standard library in favor of the more general Ordering. Unless you have a good reason for using the former that I don't know about, the latter is probably a better choice.

It might not be much better, but if you use Ordering at least you can get rid of the ugly <% operators. I'd also recommend using the same lambda shorthand that @maasg suggested (note that you can't use it for the more complex Random lambda though):

def qsortHead[A: Ordering](xs: Stream[A]) = qsort(xs)(_.head)
def qsortLast[A: Ordering](xs: Stream[A]) = qsort(xs)(_.last)
def qsortRandom[A: Ordering](xs: Stream[A]) = qsort(xs)(ys => ys(rng.nextInt(ys.length)))

You can look at this question if you want more info on the difference between the view-bound Ordered and context-bound Ordering: What are Scala context and view bounds?

Due to the way that Scala handles generic types and does type inference, you're going to be stuck with a bunch of boilerplate pretty much no matter what. The above is probably about as succinct as you're going to be able to get.

Upvotes: 0

maasg
maasg

Reputation: 37435

For the lambda expressions making use of the passed parameter, the underscore syntax is your friend: _.head

qsort(xs)(_.head)

_.head will be translated to the full expression x => x.head

Upvotes: 1

Related Questions