1 of 28

Introduction to

Functional Programming

2 of 28

Agenda

* Show some functional programming and try to sell it to you.

3 of 28

Disclaimer

* May clash with some of the Google’s style guide and best practices because of the nature of the languages that we use.

* The syntax might not be accurate at some places.

* The aim of this talk is not to hurt any language’s or programmer’s emotions.

4 of 28

Immutability

a = 5;

b = func(a);

print(a);

// What should a be?

5 of 28

Immutability

a = 5;

b = func(a);

print(a);

// What should a be?

a = [1, 2, 3];

b = func(a);

print(a);

// What should a be?

6 of 28

Immutability

a = 5;

b = func(a);

print(a);

// What should a be?

a = [1, 2, 3];

b = func(a);

print(a);

// What should a be?

func(a) -> func2(a) -> func3(a) -> . . . -> func545145564(a) { a[1] = 10; }

7 of 28

Immutability

a = 5;

b = func(a);

print(a);

// What should a be?

a = [1, 2, 3];

b = func(a);

print(a);

// What should a be?

func(a) -> func2(a) -> func3(a) -> . . . -> func545145564(a) { a[1] = 10; }

8 of 28

Immutability

* Mutability leads to inconsistent APIs.

9 of 28

Immutability

* Mutability leads to inconsistent APIs.

a = “abc”;

a2 = a.capitalize();

// What can a and a2 be?

10 of 28

Immutability

* Mutability leads to inconsistent APIs.

a = “abc”;

a2 = a.capitalize();

// What can a and a2 be?

a

a2

“abc”

“ABC”

“ABC”

null/undefined etc.

“ABC”

“ABC”

11 of 28

Immutability

* Mutability leads to inconsistent APIs.

a = “abc”;

a2 = a.capitalize();

// What can a and a2 be?

a

a2

“abc”

“ABC”

“ABC”

null/undefined etc.

“ABC”

“ABC”

12 of 28

Immutability

* All values are immutable.

* A value is a value: primitive or otherwise.

* You cannot edit a value passed as reference.

* Immutable data-structures, also called as persistent data structures.

* a.push(4); is bad as it changes a for all the references.

* Decouples time from computation.

* Makes programs easy to read and reason about.

a = [1, 2, 3];

b = func(a);

print(a);

// What should a be?

13 of 28

What. Not how. (Higher order functions)

in = [1, 2, 3];

out = []; // How

for (i = 0; i < in.length; i++) { // How

out[i] = in[i] * 2; // What

}

14 of 28

What. Not how. (Higher order functions)

in = [1, 2, 3];

out = []; // How

for (i = 0; i < in.length; i++) { // How

out[i] = in[i] * 2; // What

}

out2 = []; // How

for (i = 0; i < in.length; i++) { // How

out2[i] = in[i] * 3; // What

}

15 of 28

What. Not how. (Higher order functions)

in = [1, 2, 3];

out = []; // How

for (i = 0; i < in.length; i++) { // How

out[i] = in[i] * 2; // What

}

// map :: ((a -> b), [a]) -> [b]

// Encapsulates the how in one place

def map(func, arr) {

if (arr.length === 0) {

return [];

} else {

return [func(head(arr))] ++ map(func, tail(arr));

}

}

// No for loops! Less moving parts. Less places to make mistakes.

out2 = []; // How

for (i = 0; i < in.length; i++) { // How

out2[i] = in[i] * 3; // What

}

16 of 28

What. Not how. (Higher order functions)

in = [1, 2, 3];

out = []; // How

for (i = 0; i < in.length; i++) { // How

out[i] = in[i] * 2; // What

}

// map :: ((a -> b), [a]) -> [b]

// Encapsulates the how in one place

def map(func, arr) {

if (arr.length === 0) {

return [];

} else {

return [func(head(arr))] ++ map(func, tail(arr));

}

}

// No for loops! Less moving parts. Less places to make mistakes.

out2 = []; // How

for (i = 0; i < in.length; i++) { // How

out2[i] = in[i] * 3; // What

}

out = map(x => x * 2, in); // What

out2 = map(x => x * 3, in); // What

17 of 28

What. Not how. (Higher order functions)

// filter :: ((a -> Bool), [a]) -> [a]

def filter(predFunc, arr) {

if (arr.length === 0) {

return [];

} else {

h = head(arr);

return (predFunc(h) ? [h] : []) ++ filter(predFunc, tail(arr));

}

}

// No for loops!

18 of 28

What. Not how. (Higher order functions)

// reduce :: ((a, b) -> b, b, [a]) -> b

def reduce(accFunc, acc, arr) {

if (arr.length === 0) {

return acc;

} else {

h = head(arr);

return reduce(accFunc, accFunc(acc, h), tail(arr));

}

}

// No for loops!

19 of 28

What. Not how. (Higher order functions)

// reduce :: ((a, b) -> b, b, [a]) -> b

def reduce(accFunc, acc, arr) {

if (arr.length === 0) {

return acc;

} else {

h = head(arr);

return reduce(accFunc, accFunc(acc, head), tail(arr));

}

}

// No for loops!

reduce(add2, 0, [1, 2, 3])

-> reduce(add2, add2(0, 1), [2, 3])

-> reduce(add2, 1, [2, 3])

-> reduce(add2, add2(1, 2), [3])

-> reduce(add2, 3, [3])

-> reduce(add2, add2(3, 3), [])

-> reduce(add2, 6, [])

-> 6

(((0 + 1) + 2) + 3)

20 of 28

Todo

* Try to implement map, filter and reduce in your language.

* Try to implement map and filter using reduce.

21 of 28

Example

* Multiply all even numbers in an array by 10 and add them.

22 of 28

Example

const numList = [1, 2, .., 10];

let result = 0;

for (let i = 0; i < numList.length; i++) {

if (numList[i] % 2 === 0) {

result += numList[i] * 10;

}

}

* Multiply all even numbers in an array by 10 and add them.

23 of 28

Example

const numList = [1, 2, .., 10];

let result = 0;

for (let i = 0; i < numList.length; i++) {

if (numList[i] % 2 === 0) {

result += numList[i] * 10;

}

}

const result =

[1, 2,.., 10]

.filter(n => n % 2 === 0) // filter even numbers: [2, 4, 6, 8, 10]

.map(a => a * 10) // multiply each by 10: [20, 40, 60, 80, 100]

.reduce((a, b) => a + b, 0); // add them: 300

* Multiply all even numbers in an array by 10 and add them.

24 of 28

Example

const numList = [1, 2, .., 10];

let result = 0;

for (let i = 0; i < numList.length; i++) {

if (numList[i] % 2 === 0) {

result += numList[i] * 10;

}

}

// all the hows are mixed together

// all the whats are mixed together

// all the hows and whats are mixed together

const result =

[1, 2,.., 10]

.filter(n => n % 2 === 0) // filter even numbers: [2, 4, 6, 8, 10]

.map(a => a * 10) // multiply each by 10: [20, 40, 60, 80, 100]

.reduce((a, b) => a + b, 0); // add them: 300

// clear separation of concerns

// easier to read, reason about and debug

// less cognitive load

// more extensible

// more malleable

* Multiply all even numbers in an array by 10 and add them.

25 of 28

What. Not how.

* Decouple what and how.

* You focus on what, not how.

* Increases reusability.

* Increases modularity.

* You think in terms of small do-one-thing functions.

26 of 28

Pointers (not the C ones)

* Use recursion. Avoid for loops.

* Referential transparency/pure functions: No reading apart from arguments, no writing to any other place. No side effects. Helps you to reason about your code easily.

* Try to avoid updating current state of data in your mind. Functions do not act on data. Functions take arguments and return results.

* Try to group your side effects towards the outer shell.

* A program is a transformation of data going through functions rather than state updates on an object.

* a.update(b) becomes a2 = update(a, b)

27 of 28

Recommendations

* Learn one functional programming language: Clojure, Elixir, Haskell

* Makes you a better programmer. Adds tools to your toolbelt. You know more patterns.

* It will seem very restrictive at first but once you get the hang of it, it’s a lot of fun!

28 of 28

Questions???