Functional Programming for Mere Mortals (Part 1)


Melon

This is the first post in a series of blog posts where I work my way through the “Functional Programming in Scala” book.

A couple of years ago, I took an online class called “Functional Programming in Scala”, taught by the creator of Scala, Martin Odersky. I found the class fun and challenging.

I then picked up the book “Functional Programming in Scala” and worked part of the way through it. I also participated in a study group built around it at my old company, run by a co-worker of mine.

Through it all, I felt that there were concepts that I struggled with and my lack of understanding sometimes showed when looking at existing Scala codebases (i.e Twitter Finagle).

So this is my second run through the book. I’m giving myself enough time to work through each exercise (and there are quite a few of them) and making copious notes as I go. This blog post is the first in a series and covers chapter 1 (‘What is Functional programming) and 2 (‘Getting Started with Functional Programming in Scala’)

This is by no means meant to be a comprehensive tour through Functional Programming, and in some ways, is very specific to how I learn and the concepts that I had difficulty with.

However, I am hoping that it can be helpful to there people.Also, I doubt this post will make much sense without having a copy of the book with you.

Lets dive in.

Chapter 1 opens with

Functional programming (FP) is based on a simple premise with far-reaching implications: we construct our programs using only pure functions — in other words, functions that have no side effects and the rest of the chapter proceeds to explain what that means with a worked example. We don’t really get into the meat of things (and into the exercises) until Chapter 2, that also introduces Scala the language.

If you’re coming from another programming language (i.e. Java, C#, Ruby, Python etc), Scala looks like a lot of other languages. Even the section on high order functions (functions that take other functions) is something that can be done in other languages.

If this were Lord of the Rings, curry/uncurry is the part where someone would exclaim “What is this new devilry?!”. The universe has a sense of humor, and currying is named not after the the food, but named after the mathematician Haskell Curry (the Haskell programming language is also named after him).

The Wikipedia definition is

currying is the technique of translating the evaluation of a function that takes multiple arguments (or a tuple of arguments) into evaluating a sequence of functions, each with a single argument. Currying is related to, but not the same as, partial application.

Curry converts a function of N arguments to a function of N-1 arguments. The type signature indicates what is happening.

def curry[A,B,C](f: (A, B) => C): A => (B => C)

This reads “curry is a function that operates on types of type A, B and C. It takes a function f that takes a type of A and B and returns C. It returns a function that takes a type A and returns a function that takes a type B and returns a value of type C”.

My solution (the {} is not needed but I have it there for readability);

def curry[A,B,C](f: (A, B) => C): A => (B => C) = {
    (a: A) => (b:B) => f(a,b)
}

and sample usage;

val func1 = (a: Int, b: Double) => a * b
val curried = curry(func1)
val result1 = curried(9)
val result2 = result1(3)
assert(result2 == 27)

The reverse of curry is uncurry, which reverses the transformation. The type signature is

def uncurry[A,B,C](f: A => B => C): (A, B) => C

which reads “uncurry is a function that operates on types of A, B and C. It takes a function f that takes a type of A and returns a function that takes a type of B and returns a type of C, and returns a function that takes a value of type A, a value of type B and returns a value of type C” (a bit of a mouthful)

My solution;

def uncurry[A,B,C](f: A => B => C): (A, B) => C = {
    (a, b) => f(a)(b)
}

and sample usage;

val curried = curry(func1) 

val result1 = curried(Hello)

val result2 = result1(There!)

assert(result2 == Hello There!)

val uncurried = uncurry(curried)

val result3 = uncurried(Hello, There again!)

assert(result3 == Hello There again!)

val func1 = (a: String, b: String) => a +   + b

I struggled a bit with uncurry before arriving at the solution.

The final new concept was compose, which composes two functions create a new one.

The type signature is;

def compose[A,B,C](f: B => C, g: A => B): A => C

My solution;

def compose[A,B,C](f: B => C, g: A => B): A => C = {
    (a) => f(g(a))
}

and sample usage;

val func1 = (a: Int) => a.toString()

val func2 = (b:String) => b +  times

val composed = compose[Int, String, String](func2,func1)

val result = composed(33)

assert(result == 33 times)

So chapter 2 just starts scratching the surface. Chapter 3 (next post) gets much deeper.

All the code I’m writing to work through the exercises is here;

Scala for Mere Mortals

Article originally published here

2022

2020

2019

2017

2016

2012

2008