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

Scala Functional Design & Programming - Chapter 2 (2)

about7mins to read

Table of Contents

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

amazon img

This time, I'll cover up to Chapter 2. It's about processing loops and types.

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

Chapter 2

In Chapter 2, there's a brief explanation of Scala.
Then, it explains how to write loops using recursion and touches on tail recursion.
Here, practice problems are introduced.

Create a recursive function to get the Fibonacci sequence. However, define it as a tail recursive function.

There was an example of factorial just before, but for Fibonacci, we need to use the previous two values, so we need to increase the number of arguments cleverly.
I wrote the following program.
Since it's a tail recursive function, it's okay even with 1000 (although it will overflow due to the Int type).

import scala.annotation.tailrec

object Main extends App {
  def fib(n: Int): Int = {
    @tailrec
    def go(n: Int, pre: Int, prepre: Int): Int =
      if(n <= 0) prepre
      else go(n-1, pre + prepre, pre)
    go(n, 1, 0)
  }

  (0 to 1000).foreach( i => println( fib(i) ))
}

Next, it explains higher-order functions and polymorphism.
It's interesting that these concepts are introduced early on, unlike in a C++ beginner's book, where templates are introduced later.
Here, another practice problem appears.

Create a function that takes a comparison function and determines if the array is sorted.

We can create it in the same way as the function that searches for an element in an array, which was introduced just before.

import scala.annotation.tailrec

object Main extends App {
  def isSorted[A](as: Array[A], ordered: (A,A) => Boolean): Boolean = {
    @tailrec
    def loop(n: Int): Boolean = {
      if(n >= as.length - 1) true
      else if(! ordered(as(n), as(n+1))) false
      else loop(n+1)
    }
    loop(0)
  }

  val test = Array(1, 2, 2, 3)
  println(isSorted(test, (a:Int, b:Int) => a <= b))
  println(isSorted(test, (a:Int, b:Int) => a < b))
}

It then demonstrates examples of function literals and type-based restrictions using partial applications.
It's like solving a puzzle to decide on the implementation based on the type.

From here, there's a torrent of practice problems.
The task is to create curry, uncurry, and compose functions.

object Main extends App {
  // ex 1
  def curry[A, B, C](f: (A, B) => C): A => (B => C) =
    (a: A) => (b: B) => f(a, b)

  def test(a: Int, b: Float): (Float, Double) = (a.toFloat, b.toDouble)
  val t = curry(test)
  val res = t(10)
  println(res(2.5f))

  // ex 2
  def uncurry[A, B, C](f: A => B => C): (A, B) => C = (a: A, b: B) => f(a)(b)

  val t2 = uncurry(t)
  println(t2(10, 2.5f))

  // ex 3
  def compose[A, B, C](f: B=> C, g: A=>B): A => C = (a: A) => f(g(a))

  val t3 = compose(
    (b: Int) => b.toDouble,
    (a: Float) => a.toInt
  )
  println(t3(10.5f))
}

Thoughts

It feels like creating a universal process and combining it, like building a library.
Recently, with the increasing number of large-scale projects and the overhead of specification changes, I feel that the need to design and write abstract processes is higher than ever.
In that sense, learning functional programming has value in cultivating such abilities.

Continued:

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

Share