The Road to Functional Programming

Educational material to learn functional programming in Scala, from scratch, in a structured and comprehensive way.

View project on GitHub

Proposed solutions for exercises

Chapter 4 - Pure functions and referential transparency

Exercises 4.1

4.1.1, 4.1.2, 4.1.3

Create a pure function String => String that associates each input string into its uppercase string.

Create a pure function Int => Boolean that associates even numbers with the value true and odd numbers with the value false.

Using your result of the exercise of animals in the case classes chapter, create a pure function with signature Animal => String that given an animal it returns the type of animal.

def toUpperCase(input: String): String = input.toUpperCase()

// Returning a function
def isEven: Int => Boolean = _ % 2 == 0

// Same as Chapter 3, Exercises 2
trait Animal
case class Cat(name: String, age: Int) extends Animal
case class Dog(name: String) extends Animal
case class Dolphin(name: String, weight: Double) extends Animal

def animalToString(animal: Animal): String = animal match {
  case Cat(_, _)     => "Cat"
  case Dog(_)        => "Dog"
  case Dolphin(_, _) => "Dolphin"
}

Exercise 4.2

4.2.1

We want to work with a counter and write two functions to increment/decrement its value of a given amount. First solve this exercise writing a function in imperative style and then try to solve the same problem but using only pure functions. What’s the problem you’re encountering?

var counter: Int = 0

def incrementImperative(amount: Int): Unit = {
  counter += amount
}

def incrementPure(counter: Int, amount: Int): Int = {
  counter + amount
}

// Checking initial value
counter
// Output:
//   Int = 0

// Incrementing and display counter
incrementImperative(5)
counter
// Output:
//   Int = 5

// Incrementing a displaying counter
incrementPure(counter, 3)
counter
// Output:
//   Int = 8
//   Int = 5

4.2.2

Write a pure function that discovers the maximum integer in a list of positive integers List[Int] => Int and returns -1 if the list is empty or if there are negative numbers or any other sort of issues. Solve the exercise without using scala .max() function but using mutable variables and a for loop. Is it still a pure function? Why?

def maxPositive(input: List[Int]): Int = {
  if (input.isEmpty || input.exists(_ < 0)) -1
  else {
    var max = 0
    for (x <- input)
      max = Math.max(max, x)
    max
  }
}

maxPositive(List(0, 6, 12, 7))
maxPositive(List())
maxPositive(List(0, -3, 12, 7))

// Output:
//    Int = 12
//    Int = -1
//    Int = -1

4.4.3

How can you solve the previous exercise if we want the function to be able to work on a list that contains any integer and not just positive integers? You now need to express a situation where you can’t use the type Int to represent an “exceptional” situation because Int is part of your normal output.


// Using a tuple to represent if a result is valid or not
type ValidatedResult = (Boolean, Int)
def max1(input: List[Int]): ValidatedResult = {
  if (input.isEmpty) (false, 0)
  else {
    var max = 0
    for (x <- input)
      max = Math.max(max, x)
    (true, max)
  }
}

// Using Option to represent the same thing
def max2(input: List[Int]): Option[Int] = {
  if (input.isEmpty) None
  else {
    var max = 0
    for (x <- input)
      max = Math.max(max, x)
    Some(max)
  }
}

// Throwing an exception, but that would disrupt the normal
// execution flow
def max3(input: List[Int]): Int = {
  if (input.isEmpty) throw new IllegalArgumentException()
  else {
    var max = 0
    for (x <- input)
      max = Math.max(max, x)
    max
  }
}

max1(List(0, 6, 12, 7))
max1(List())
max1(List(0, -3, 12, 7))

// Output:
//   (Boolean, Int) = (true, 12)
//   (Boolean, Int) = (false, 0)
//   (Boolean, Int) = (true, 12)

max2(List(0, 6, 12, 7))
max2(List())
max2(List(0, -3, 12, 7))

// Output:
//   Option[Int] = Some(12)
//   Option[Int] = None
//   Option[Int] = Some(12)

max3(List(0, 6, 12, 7))
max3(List())
max3(List(0, -3, 12, 7))

// Output:
//   Int = 12
//   java.lang.IllegalArgumentException
//   Int = 12

Exercise 4.3

4.3.1

Write a pure function List[A] => Int that counts the number of elements in the given list. Be mindful to not use mutable variables. Is it possible at all?

// It's not possible!