Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Step-by-step connection between a Scala high-order function to provided examples

I'm having difficulty figuring out how to make the jump from a Scala high-order function definition to the example provided. It was provided in this slide show on slide 81.

Here's the high-order function definition:

trait X[A] { def map[B](f: A => B): X[B] }

Here's the examples provided:

(1 to 10) map { x => x * 2 } // evaluates to Vector(2, 4, ..., 20)
(1 to 10) map { _ * 2 }      // shorthand!

Huh?! There just HAS to be some steps in here I am missing. I get that the examples may be leveraging both the function definition AND some Scala niceties. I just don't have enough experience reading Scala and making the connecting assumptions yet.

My background is as a Java OO. I am now learning Scala and functional programming. And this is not the first example like this I have not understood. It's just the first one where I felt I had the courage to post knowing I would look ignorant.

I did try to research this. First, I went to the Scala "bible", "Programming in Scala 2nd Edition", and attempted to make sense of if from there (pages 165-9). Then, I did a search here on StackOverflow. And I found several links that talk around the area. But, nothing actually shows me, STEP-BY-STEP, the connection between a Scala high-order function definition and the provided examples in a way that maps to the particular instance in this slide.

Here's what I found on StackOverflow:

  1. Scala: Workshop Advice
  2. More on generic Scala functions
  3. Scala: How to define "generic" function parameters?

I'm just now realizing that I skipped Google and came straight to StackOverflow. Hmmm. If you google and find just the right link, I would love seeing it. I've run out of time to sift through all the Google links which use terms like monkey-monad, blastomorphisms, etc. while leaving me even more confused and less likely to try and figure this out.

like image 232
chaotic3quilibrium Avatar asked Feb 26 '12 15:02

chaotic3quilibrium


2 Answers

I think the following is just an example signature provided for the purpose of displaying some of Scala's collection properties. In particular it does not show any implementation so you cannot really connect all the dots. Also it's not actually consistent with the examples... So, may be this is confusing.

trait X[A] { def map[B](f: A => B): X[B] }

I would read that as: given a collection class X over elements of type A:

  • it has a map function that is parameterized on a type B
  • the map function takes a function f converting a single A to a single B
  • map returns a collection of the same type X over elements of type B.

Then it jumps to the example to illustrates using:

(1 to 10) map { x => x * 2 }

So, connecting the dots:

  • The collection X is the type of (1 to 10), here a Range
  • f: A => B is x => x * 2 which is inferred as a function taking an Int and returning and Int.
  • Given the signature you would think that would return a Range over Int, but this actually returns an IndexedSeq.

A better example may have been:

List(1, 2, 3).map(i => i + "!") // a List[Int]
// returns a List[String]: List("1!", "2!", "3!") 
like image 115
huynhjl Avatar answered Nov 15 '22 20:11

huynhjl


A higher-order function (or method) is a function/method which either takes a function as its parameter or yields a function as its result or both.

In this case it is a method called map defined on things like lists, arrays as well as many other kinds of containers. When called on a 1 to 10 which is a range of numbers from 1 to 10, represented by Range[Int] in Scala it traverses them one by one and applies the function (the one which has been passed in as a parameter) to every number inside of the range. The results of this function are accumulated in a new container - Vector[Int] in this case, which gets returned as the result of the map method.

So (1 to 10) map { x => x * 2 } which is btw syntactic sugar for (1 to 10).map(x => x * 2) applies x => x * 2 to numbers from 1 to 10. You can think of it as a call-back function. You could also have written it like this:

(1 to 10).map( new Function1[Int, Int] {
   override def apply(x: Int) = x * 2
})
like image 23
agilesteel Avatar answered Nov 15 '22 20:11

agilesteel