text: Scala at Light Speed, Part 3: Functional Programming
  Scala at Light Speed, Part 3: Functional Programming
  Check out this post to learn more about functional programming in Scala. basics: values, expressions, types
  - Object-orientation: classes, instances, singletons, methods, and basic generics
  You may also like: Scala at the Speed of Light, Part 1: The Essentials, and Part 2: Object Orientation
  What Is a Function?
  From the previous part, you remember that Scala has the special
  apply method that allows instances of classes (or singleton objects) to be invoked like functions:
  class Person(name: String) {
  def apply(age: Int) = println(s"I have aged $age years")
  }
  val bob = new Person("Bob")
  bob.apply(43)
  bob(43) // INVOKING bob as a function === bob.apply(43)
  Also, let's recap a few points:
  - Scala runs on top of the JVM.
  - The JVM was built for Java, which is an OO language.
  - Scala is a functional programming language, meaning we work with functions like any other values: we pass them around, compose them, return them as results.
  To fulfill the functional programming ideal, Scala comes with the following traits (simplified):
  xxxxxxxxxx
  trait Function1[T, R] {
  def apply(argument: T): R
  }
  trait Function2[T1, T2, R] {
  def apply(arg1: T1, arg2: T2): R
  }
  //... all the way to Function22
  Because apply allows us to invoke instances like functions, we can easily write:
  xxxxxxxxxx
  val simpleIncrementer = new Function1[Int, Int] {
  override def apply(arg: Int): Int = arg + 1
  }
  val newValue = simpleIncrementer(23) // same as simpleIncrementer.apply(23)
  We've just defined a function!
  Scala function values are instances of Function1, Function2, ... Function22, which are nothing but simple traits with an
  apply method.
  Looks Like Functional Programming
  In functional programming, we work a lot with function values. Constructing them as an anonymous class every time would be a pain. Scala has syntactic sugar for creating function values:
  xxxxxxxxxx
  val doublerFunction = (x: Int) => x * 2
  /*
  same as:
  val doublerFunction = new Function1[Int, Int] {
  override def apply(x: Int) = x * 2
  }
  */
  The type of function defined above is
  Function1[Int, Int], or
  Int => Int for short (looks similar to Haskell in that regard).
  For those with real typing anxiety, Scala has an even more shorthand notation:
  xxxxxxxxxx
  val shortIncrementer: Int => Int = _ + 1 // same as (x: Int) => x + 1
  val multiplier: (Int, Int) => Int = _ * _ // same as (x: Int, y: Int) => x * y
  As long as the compiler knows the function type (as I explicitly declared), you can use underscores for each different argument of the function. This shorthand notation is particularly useful for long method chains with function arguments.
  HOFs
  Methods or functions taking other functions as arguments or returning functions as results are called higher-order functions (HOFs).
  Some classical HOFs we use a lot with collections are
  map,
  flatMap, and
  filter. Let's take them in turn as examples.
  A collection's
  map method will take a function as an argument and will return a new collection containing the applications of the function on every element:
  xxxxxxxxxx
  val aMappedList: List[Int] = List(1,2,3).map(x => x + 1) // or .map(_ + 1), same thing
  // List(2,3,4)
  A collection's
  flatMap method takes a function from an element to another collection. The applications of the function on every element will return many small collections, which will be finally concatenated in the returned collection.
  xxxxxxxxxx
  val aFlatMappedList = List(1,2,3).flatMap { x =>
  List(x, 2 * x)
  }
  // alternative syntax, same as .map(x => List(x, 2 * x))
  // returns List(1,2,2,4,3,6) as the concatenation of [1,2], [2,4] and [4,6]
  A collection's
  filter method takes a function from an element to Boolean, and returns a new collection containing just the elements for which the function returns true.
  xxxxxxxxxx
  val aFilteredList = List(1,2,3,4,5).filter(_ <= 3)
  // List(1,2,3)
  Combining
  map,
  flatMap, and
  filter is a powerful technique to manipulate collections. An example: all the pairs from combining a number from the list [1,2,3] with a character from the list [a,b,c]:
  xxxxxxxxxx
  val allPairs = List(1,2,3)
  .flatMap(number => List('a', 'b', 'c').map(letter => s"$number-$letter"))
  So, for every number, we take the list of characters, and for every one, we combine the number and the letter.
  This is the style of thinking we use in Scala and functional programming. Instead of iterating through a collection and manually constructing the values, we are manipulating the existing collections through their higher-order functions. Of course, "manipulating" is an improper term because we work with immutable data structures, so we always return a new collection.
  These map/flatMap/filter chains can be very long in practice, and thus become increasingly hard to read. Scala offers another syntax sugar for these large map/flatMap/filter chains in the form of for-comprehensions:
  xxxxxxxxxx
  val alternativePairs = for {
  number <- List(1,2,3)
  letter <- List('a','b','c')
  } yield s"$number-$letter"
  // equivalent to the map/flatMap chain above
  Misperception to dispel right off the bat: this is not a for loop. It's an expression because it reduces to a value. The value is computed by the map/flatMap/filter chain, which the compiler reconstructs for you when you write a for-comprehension. If your data structure doesn't offer the appropriate
  map/
  flatMap/
  withFilter methods, it will not be eligible for for-comprehensions and the compiler will tell you that.
  A Brief Collections Overview
  By far, the most common data structure is a list. In the standard library, it's implemented as a singly linked list. The fundamental methods are
  head (first element),
  tail (remainder of the list), and
  :: (prepending an element).
  xxxxxxxxxx
  val aList = List(1,2,3,4,5)
  val firstElement = aList.head
  val rest = aList.tail
  val aPrependedList = 0 :: aList // List(0,1,2,3,4,5)
  val anExtendedList = 0 +: aList :+ 6 // List(0,1,2,3,4,5,6)
  The supertype for all ordered collections of elements is
  Seq (for sequence). The fundamental method is the
  apply method, which accesses an element at a given index in the sequence.
  xxxxxxxxxx
  // sequences
  val aSequence: Seq[Int] = Seq(1,2,3) // Seq.apply(1,2,3)
  val accessedElement = aSequence(1) // the element at index 1: 2
  For large sequential data in memory,
  Vector is a fast Seq implementation (implemented as a full 32-ary tree). It has the same API as a Seq.
  xxxxxxxxxx
  // vectors: fast Seq implementation
  val aVector = Vector(1,2,3,4,5)
  Sets are also useful, because they contain no duplicates.
  Set is just a trait, so the
  Set companion's apply method returns some implementation of
  Set (usually some hash set). The fundamental methods are
  contains (check if an element is in the set),
  + and
  - (for adding and removing elements).
  xxxxxxxxxx
  // sets = no duplicates
  val aSet = Set(1,2,3,4,1,2,3) // Set(1,2,3,4)
  val setHas5 = aSet.contains(5) // false
  val anAddedSet = aSet + 5 // Set(1,2,3,4,5)
  val aRemovedSet = aSet - 3 // Set(1,2,4)
  Ranges are useful for generating numbers. They have the same API as a Seq, but don't need to actually contain all the numbers.
  xxxxxxxxxx
  // ranges
  val aRange = 1 to 1000
  val twoByTwo = aRange.map(x => 2 * x).toList // List(2,4,6,8..., 2000)
  Don't ask about the
  to operator above (for now). Notice instead that we can convert in between various collections with
  toList,
  toSet,
  toSeq etc.
  Finally, multi-type collections. Starting with
  tuples, which are groups of values under the same value (Python folks should be familiar):
  xxxxxxxxxx
  // tuples = groups of values under the same value
  val aTuple = ("Bon Jovi", "Rock", 1982)
  And for key-value associations, we have
  maps with their fundamental methods exemplified below.
  xxxxxxxxxx
  // maps
  val aPhonebook: Map[String, Int] = Map(
  ("Daniel", 6437812),
  "Jane" -> 327285 // same as ("Jane", 327285)
  )
  val aNewPhonebook = aPhonebook + ("Mary" -> 5731) // add/replace association
  val removedDaniel = aPhonebook - "Daniel" // remove key
  val hasJane = aPhoneBook.contains("Jane")
  val danielsNumber = aPhonebook("Daniel") // beware this can throw if key not present
  In the next part, we will talk about one of Scala's most powerful features: pattern matching.
  Further Reading
  Clean Code Best Practices in Scala
  [DZone Refcard] Getting Started With Scala
  Opinions expressed by DZone contributors are their own.
  {{ parent.title || parent.header.title}}
  {{ parent.tldr }}
  {{ parent.linkDescription }}{{ parent.urlSource.name }}