An introduction to Scala functional programming

Scala is designed to allow the functional programming style. But what does Scala functional programming actually mean? Let’s start with the fact that functional programs are immutable.

Immutable software

For example, in regular programming you initialize a variable to some value:

x = 1
return x * 2

This will return 2. But the value of the program can change when another programmer checks out that code and changes the value of x.

With functional programming, there are no global variables. Everything is a function. So the output is always the same. In other words:

function (x) return x * 2

Functional programs are written like math statements. Since there are no global variables, everything must be a function. And since everything must be a function, you need to check that these are completely implemented and not applied to invalid inputs. For example, there is the concept of domains, partially-applied functions, and pattern matching. All of these check to see that the program can handle whatever value is passed to the program without causing it to crash.

Let’s look at each of these concepts.

Domain

In math, the domain of a function is the range of values for which the function is valid. For example, the domain of the function sqrt (square root) is x >= 0 since the square root of negative numbers is not defined (Well, they are. They are called complex numbers, i. ).

We write the domain of a function f as {f(x): x ∈ R, >= 0}. This says the domain of x is any real number that is non-negative.

We can express this in Scala using partial functions.

In the function sr, if we did not use the word PartialFunction, the compiler would complain that we are not handling all values.

Below we defined a function that takes a Double and returns a Double. We check that the input is bigger than or equal to zero. If it is, then we return the square root. The sr.isDefinedAt() checks to see that the value we want to pass it is in the domain of the function, i.e., is applied.

import java.lang.Math

val sr: PartialFunction[Double, Double] = {
  case d: Double if d >= 0 => Math.sqrt(d)
}


sr.isDefinedAt(-1)
res7: Boolean = false

Higher Order Functions

Higher order functions let you break down a complex function into steps. If you remember your math from college, these are called composite functions:

That is f(g(x)), which is read as f of g of x.

For example, we can break the statement 2x – 2 into two steps:

g(x) = 2x
f(g(x)) = g(x) - 2

We can do that in Scala, because in Scala functional programming, you can pass functions as arguments. In function f below, g is a function that returns an Int.

def g(x: Int): Int = { x * 2}
def f(g: Int=> Int, x: Int) : Int = {g(x) - 2}
Here is the result.
f(g,2)
res11: Int = 2

How to curry a function

Currying a function means to apply nested functions instead of applying the same operation over each item in a collection. One obvious candidate for that is addition.

For example, to add two number you would write:

def add1(x:Int, y:Int): Int = x + y

Run that:

add1(2,3)
res15: Int = 5

But now we write a new function that takes an Int and returns a function that returns another Int. When you run that function, it saves its value. Run it again and it adds that value to whatever you passed it the first time. So x + y keeps a running sum:

def add2(x: Int):Int=>Int = y=> x + y

Run it two times:

add2(1)(2)
res20: Int = 3

This is easier to understand if you run this just one time:

add2(2)
res16: Int => Int = <function1>

So we can call this function as many times we want to make an adding machine.

Recursive functions

Functions can call themselves. Let’s calculate n! (n factorial) which is:

 n * (n -1) * (n - 2) … For example, 3! = 3 * 2 * 1.

We can take a shortcut and help the function by writing, in this case, 3 as List(1,2,3) instead of just 3, thus handing the Scala function each value it needs.

The notation x::tail tells the program to take the first and last elements from the list. It iterates over every item in the list 1,2,3 including the empty list Nil. And since all functions have values, this one keeps a running tally of the value of factorial, which makes it iterative or recursive.

def factorial(ints: List[Int]): Int = ints match { 
  case Nil => 1
  case x :: tail => x * factorial(tail)
}

Run it:

factorial(List(1,2,3))
res30: Int = 6

This Scala code is easier to understand if we use addition:

def sum(ints: List[Int]): Int = ints match { 
  case Nil => 0
  case x :: tail => x + sum(tail)
}

Results in:

sum(List(1,2,3))
res33: Int = 6

And while there’s certainly more to learn, that is a quick synopsis of how to do Scala functional programming.