header source
my icon
esplo.net
ぷるぷるした直方体
Cover Image for Scala Functional Design & Programming - Chapter 3 (3)

Scala Functional Design & Programming - Chapter 3 (3)

about9mins to read

I bought "Scala Functional Design & Programming - A Comprehensive Guide to Functional Programming by Scalaz Contributors".
I'll read it bit by bit and summarize each chapter.

amazon img

This time, I'll cover up to Chapter 3. The main topic is data updates using pure functions, which is a key aspect of functional programming.

https://www.esplo.net/posts/2016/09/sfdp-2

Chapter 3

This chapter focuses on how to update data using pure functions, which do not have side effects. It starts with the definition of a list and explains pattern matching.

There's a simple quiz on pattern matching (omitted).

Next, it discusses how to take advantage of the fact that data is immutable to reduce memory usage. This is followed by a series of exercises.

Implement tail, setHead, drop, dropWhile, and init for lists.

These exercises are designed to help you understand how to work with lists in a functional programming style.

  def tail[A](l: List[A]): List[A] = l match {
    case Cons(_, xs) => xs
    case Nil => Nil
  }

  def setHead[A](l: List[A], h: A): List[A] = l match {
    case Cons(_, xs) => Cons(h, xs)
    case Nil => Nil
  }

  def drop[A](l: List[A], n: Int): List[A] = {
    if(n <= 0)
      l
    else {
      l match {
        case i =>
          l match {
            case Cons(_, xs) => drop(xs, n - 1)
            case _ => l
          }
      }
    }
  }

  def dropWhile[A](l: List[A], f: A => Boolean): List[A] = l match {
    case Cons(x, xs) if f(x) => dropWhile(xs, f)
    case _ => l
  }

  def init[A](l: List[A]): List[A] = l match {
    case Cons(_, Nil) => Nil
    case Cons(x, xs) => Cons(x, init(xs))
    case Nil => Nil
  }

The following is test code:

object Main extends App {
  val x = List(1,2,3,4,5)
  val y = List()

  println("  ## ex 3.2")
  println(List.tail(x))
  println(List.tail(y))

  println("  ## ex 3.3")
  println(List.setHead(x, 10))
  println(List.setHead(y, 10))

  println("  ## ex 3.4")
  println(List.drop(x, 1))
  println(List.drop(x, 4))
  println(List.drop(x, 10))
  println(List.drop(y, 1))

  println("  ## ex 3.5")
  println(List.dropWhile(x, (a:Int)=> a < 4))
  println(List.dropWhile(x, (a:Int)=> a > 4))
  println(List.dropWhile(x, (a:Int)=> a < 100))

  println("  ## ex 3.6")
  println(List.init(x))
  println(List.init(y))
}

The drop function is a bit messy, but it's a good exercise.

Next, the book introduces foldRight and foldLeft, which are essential functions in functional programming.

Implement product using foldRight.

  def product(l: List[Double]): Double = foldRight(l, 1.0)(_ * _)

Implement length using foldRight.

  def length[A](l: List[A]): Int = foldRight(l, 0)((_, y) => y + 1)

Implement foldLeft, which is tail-recursive.

  @tailrec
  def foldLeft[A, B](l: List[A], z: B)(f: (B, A) => B): B = l match {
    case Nil => z
    case Cons(x, xs) => foldLeft(xs, f(z, x))(f)
  }

Implement sum, product, and length using foldLeft.

  def flSum(l: List[Int]) = foldLeft(l, 0)(_ + _)
  def flProduct(l: List[Double]) = foldLeft(l, 1.0)(_ * _)
  def flLength[A](l: List[A]): Int = foldLeft(l, 0)((x,y) => x + 1)

Implement reverse using foldLeft.

  def reverse[A](l: List[A]): List[A] = foldLeft(l, Nil: List[A])((x,y) => Cons(y, x))

Implement foldRight using foldLeft.

  def foldLeft2[A, B](l: List[A], z: B)(f: (B, A) => B): B = {
    val f2: (A, B) => B = (a: A, b: B) => f(b, a)
    foldRight(reverse(l), z)(f2)
  }

The book also covers more advanced topics, such as implementing append, concat, plusOne, doubleToString, map, filter, and flatMap using foldRight and foldLeft.

Finally, it introduces trees as a new data structure and explains how to implement functions such as size, maximum, depth, and map for trees.

Thoughts

I was surprised by how short the implementations were. As I worked through the exercises, I started to see patterns and ways of thinking that are characteristic of functional programming.

The next chapter will cover error handling, which is an essential aspect of programming.

Share