Practical Functional Programming

An intro

Fjodor Ekström, Hugo Josefson / 2016

Overview

• Why are we doing this?
• Immutable data

• map
• filter
• ...

• Exercises

• References, Questions!

Correct programs

• Do what we mean
• Do what we expect
• ...always.

Comprehensible programs

• We can easily comprehend,
what will happen when they run

• We can easily comprehend,
what the program means

Composable programs

• Are made up of smaller parts

• Each part is Correct, Comprehensible, Composable

• Parts are swappable,
click into each other

Immutable, wat?

Mutate

• Make change in-place

• ...to data
• ...to data structure (tree, array)

Mutable data

• Data or data structure
that can be mutated
(changed in-place)

• Example:
• int variable
• array
• object with set-methods

(in many languages)

Mutate

``````let a = 1      // a == 1
let a = a + 1  // a == 2``````
``````let obj = {x: 5, y: 20}  // obj == {x:  5, y: 20}
obj.x = 10               // obj == {x: 10, y: 20}``````

Mutate

``````class Person {
int age = 0

function haveBirthday() {
this.age++
}
}

Person newBorn = new Person()
newBorn.age  // 0

newBorn.haveBirthday()
newBorn.age  // 1
``````

Mutate

``````string[] words = ["Good", "morning", "all"]

function changeTime(string newTime) {
words[1] = newTime
}

words[words.length + 1] = word
}

// ---
changeTime("afternoon") // words == ["Good", "afternoon", "all"]
addWord("the")          // words == ["Good", "afternoon", "all", "the"]
addWord("time")         // words == ["Good", "afternoon", "all", "the", "time"]``````

Immutable data

• Data or data structure
that cannot be mutated

• Example: String
(in many languages)

• Change:
• copy with some
parts replaced

Immutable data

``````string hello = "HELLO WORLD!"
string hellow = hello.toLower()

hello   //"HELLO WORLD!"
hellow  //"hello world!"

hello === hellow //false``````
``````string hello = "HELLO WORLD!"
string hellow = hello.toLower()

hello   //"HELLO WORLD!"
hellow  //"hello world!"``````

Immutable data

``````class Person {
int age = 0

function haveBirthday() {
cloneOfMe = this.cloneAndSet({ age: this.age+1 });
return cloneOfMe
}
}

Person newBorn = new Person()
Person toddler = newBorn.haveBirthday()

newBorn.age  // 0
toddler.age  // 1``````

Immutable data

``````string[] words = ["Good", "morning", "all"]

function changeTime(string[] ws, string newTime) {
clonedWords = ws.clone()
clonedWords[1] = newTime
return clonedWords
}

function addWord(string[] ws, string word) {
clonedWords = ws.clone()
clonedWords[clonedWords.length + 1] = word
return clonedWords
}

// ---
changeTime(words, "afternoon") // returns  ["Good", "afternoon", "all"]
// words == ["Good", "morning", "all"]

// returns  ["Good", "morning", "all", "the", "time"]
// words == ["Good", "morning", "all"]
``````
``````string[] words = ["Good", "morning", "all"]

function changeTime(string newTime) {
words[1] = newTime
}

words[words.length + 1] = word
}

// ---
changeTime("afternoon") // words == ["Good", "afternoon", "all"]
addWord("the")          // words == ["Good", "afternoon", "all", "the"]
addWord("time")         // words == ["Good", "afternoon", "all", "the", "time"]``````

Immutable data benefits

by code you send it to [Correct]

less (possible state mutation) to
keep track of [Comprehensible]

• Multithreading locks not needed [Correct]

• Easy to keep previous versions of state

• Optimized comparison of data structures
(compare references instead of values inside)

}

input container

mapper

output container

``````const numbers = [1, 2, 3, 4]
const doubledNumbers = []

for (let i = 0; i < numbers.length; i++) {   // imperative
doubledNumbers[i] = numbers[i] * 2       // style
}

doubledNumbers //[2, 4, 6, 8]``````
``````const numbers = [1, 2, 3, 4]
const doubledNumbers = numbers.map(number => number * 2)

doubledNumbers //[2, 4, 6, 8]``````

vs

``````const numbers = [1, 2, 3, 4]
const doubledNumbers = numbers.map(function(number) {
return number * 2
})

doubledNumbers //[2, 4, 6, 8]``````
``````const numbers = [1, 2, 3, 4]
const doubledAndIncrementedNumbers = []

for (let i = 0; i < numbers.length; i++) {
doubledAndIncrementedNumbers[i] = numbers[i] * 2 + 1
}

doubledAndIncrementedNumbers //[3, 5, 7, 9]``````
``````const numbers = [1, 2, 3, 4]

const doubledAndIncrementedNumbers = numbers
.map(number => number * 2)
.map(number => number + 1)

doubledAndIncrementedNumbers //[3, 5, 7, 9]``````

vs

``````const numbers = [1, 2, 3, 4]

const doubledAndIncrementedNumbers = numbers
.map(number => number * 2)

doubledAndIncrementedNumbers //[2, 4, 6, 8]``````

map in Java

``````String[] input = new String[]{"alice", "bob", "paul", "ellie"};

String[] output = Arrays.stream(input)
.map(s -> s.toUpperCase())
.toArray(String[]::new);

output // {"ALICE", "BOB", "PAUL", "ELLIE"}``````

map in Swift

``````let values = [2.0, 4.0, 5.0, 7.0]

let squares = values.map {\$0 * \$0}

squares // [4.0, 16.0, 25.0, 49.0]``````

map in JavaScript

``````const values = [2, 4, 5, 7]

const squares = values.map(n => n * n)     // ES2015

squares // [4, 16, 25, 49]``````
``````var values = [2, 4, 5, 7]

var squares = values.map(function (n) {    // ES5
return n * n
})

squares // [4, 16, 25, 49]``````

map in Ruby

``````[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map{|e| e*3 }

# returns [3, 6, 9, 12, 15, 18, 21, 24, 27, 30]``````

map in C#

``````List<string> words = new List<string>() {
"an", "apple", "a", "day"
};

var query = from word in words
select word.Substring(0, 1);

foreach (string s in query)
Console.WriteLine(s);

/* This code produces the following output:

a
a
a
d
*/``````

map in F#

``````let helloGood =
let list = ["a";"b";"c"]
list |> List.map (fun element -> "hello " + element)

// val helloGood : string list = ["hello a"; "hello b"; "hello c"]``````

map in Scala

``````val numbers = List(1, 2, 3, 4)
numbers.map((i: Int) => i * 2)

// List(2, 4, 6, 8)``````

map in Python

``````items = [1, 2, 3, 4, 5]
squared = list( map(lambda x: x**2, items) )

// [1, 4, 9, 16, 25]``````

map in Elm

``````map sqrt [1, 4, 9] == [1, 2, 3]

map not [True, False, True] == [False, True, False]

plusOne = (+) 1
map plusOne [1, 4, 9] == [2, 5, 10]``````

}

input container

must be at least this big:

output container

``numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]``
``numbers.filter(isGood)       //[6, 8, 10]``
``````isMoreThanFive = n => n > 5
isEven         = n => n%2 == 0
``````
``````numbers
.filter(isMoreThanFive)  //[6, 7, 8, 9, 10]
.filter(n => isEven(n))  //[6,    8,    10]
``````
``````
isGood = n => isMoreThanFive(n) && isEven(n)``````

filter in Java

``````String[] input = new String[]{"alice", "bob", "paul", "ellie"};

String[] output = Arrays.stream(input)
.filter(s -> s.length() > 4)
.toArray(String[]::new);

output // {"alice", "ellie"}``````

filter in Swift

``````let digits = [1, 4, 10, 15]
let even = digits.filter { \$0 % 2 == 0 }
// [4, 10]``````

filter in JavaScript

``````const values = [1, 4, 10, 15]

const even = values.filter(n => n%2 === 0) // ES2015

even // [4, 10]``````
``````var values = [1, 4, 10, 15]

var even = values.filter(function (n) {    // ES5
return n%2 === 0
})

even // [4, 10]``````

filter in Ruby

``````[1,2,3,4,5,6,7,8,9,10].select{|el| el%2 == 0 }
# returns [2,4,6,8,10]``````

filter in C#

``````string[] words = { "the", "quick", "brown", "fox", "jumps" };

IEnumerable<string> query = from word in words
where word.Length == 3
select word;

foreach (string str in query)
Console.WriteLine(str);

/* This code produces the following output:

the
fox
*/``````

filter in F#

``````[1..10] |> List.filter (fun i -> i%2 = 0) // even

// [2; 4; 6; 8; 10]``````

filter in Scala

``````val numbers = List(1, 2, 3, 4)
numbers.filter((i: Int) => i % 2 == 0)

// List(2, 4, 6, 8)``````

filter in Python

``````number_list = range(-5, 5)
less_than_zero = list( filter(lambda x: x < 0, number_list) )
print(less_than_zero)

# Output: [-5, -4, -3, -2, -1]``````

filter in Elm

``filter isEven [1..6] == [2,4,6]``

input container

+

output

start: 0

3

2

3

8

}

input container

return the largest of two planets

output

start: .

``````const numbers = [3, 3, 2]
const sum = numbers.reduce(
(sumSoFar, number) => sumSoFar+number,  // <-- reducer fn
0                                       // <-- init value
)

sum // 8``````
``first call to the reducer fn:    sumSoFar = 0; number = 3; sumSoFar+number = 3 ``
``second call to the reducer fn:   sumSoFar = 3; number = 3; sumSoFar+number = 6``
``third call to the reducer fn:    sumSoFar = 6; number = 2; sumSoFar+number = 8``
``// numbers.reduce(...) returns 8``
``````const numbers = [3, 3, 2]
const sum = numbers.reduce(
(sumSoFar, number) => sumSoFar+number,  // <-- reducer fn
0                                       // <-- init value
)

sum // 8``````
``const plus = (a, b) => a + b``
``````
const numbers = [3, 3, 2]
const sum = numbers.reduce(plus, 0)

sum // 8``````

reduce in Java

``````String[] input = { "this", "is", "a", "sentence" };

String output = Arrays.stream(myArray)
.reduce("", (a,b) -> a + " " + b);

// "this is a sentence"``````

reduce in Swift

``````let items = [2.0, 4.0, 5.0, 7.0]

let total = items.reduce(10.0, combine: +)

// 28.0``````

reduce in JavaScript

``````const values = [1, 4, 10, 15]

const sum = values.reduce((sumSoFar, n) => sumSoFar + n, 0) // ES2015

sum // 30``````
``````var values = [1, 4, 10, 15]

var sum = values.reduce(function (sumSoFar, n) {            // ES5
return sumSoFar + n
}, 0)

sum // 30``````

reduce in Ruby

``````[1,2,3,4,5,6,7,8,9,10].inject{|sum,e| sum += e }
# returns 55``````

reduce in C#

``````string sentence = "the quick brown fox jumps over the lazy dog";

// Split the string into individual words.
string[] words = sentence.Split(' ');

// Prepend each word to the beginning of the
// new sentence to reverse the word order.
string reversed = words.Aggregate((workingSentence, next) =>
next + " " + workingSentence);

Console.WriteLine(reversed);

// This code produces the following output:
//
// dog lazy the over jumps fox brown quick the ``````

fold in F#

``````["a";"b";"c"] |> List.fold (+) "hello: "
// "hello: abc"
// "hello: " + "a" + "b" + "c"

[1;2;3] |> List.fold (+) 10
// 16
// 10 + 1 + 2 + 3``````

fold in Scala

``````val numbers = List(1, 2, 3, 4)
numbers.foldLeft(0)((m: Int, n: Int) => m + n)
// 55``````

reduce in Python

``````from functools import reduce
product = reduce( (lambda x, y: x * y), [1, 2, 3, 4] )

# Output: 24``````

fold in Elm

``foldr (+) 0 [1,2,3] == 6``

python_exercises

Exercises avoid using anything python specific.

Recommended!

Most of them involve characters, words and phrases, rather than numbers, and are therefore suitable for students interested in language rather than math.

May be quite algorithmic / tricky.
Suggested days: 1, 4, 5, 12.
Day 5 hint: Regex (.)\1 matches double chars.

Exercises

reactivex.io/learnrx

Well-explained exercises in JavaScript.

Recommended!

References

 Java https://www.sitepoint.com/java-8-streams-filter-map-reduce/ Swift http://useyourloaf.com/blog/swift-guide-to-map-filter-reduce/ JavaScript https://danmartensen.svbtle.com/javascripts-map-reduce-and-filter Ruby http://queirozf.com/entries/ruby-map-each-collect-inject-reject-select-quick-reference C# https://msdn.microsoft.com/en-us/library/mt693038.aspx https://msdn.microsoft.com/en-us/library/mt693055.aspx https://msdn.microsoft.com/en-us/library/mt693043.aspx F# https://fsharpforfunandprofit.com/posts/list-module-functions/ Scala https://twitter.github.io/scala_school/collections.html Python http://book.pythontips.com/en/latest/map_filter.html Elm http://package.elm-lang.org/packages/elm-lang/core/latest/List

Syntax for map, filter, reduce

Thank you!

Questions!?

hugo.josefson@jayway.com
Code, slides: www.hugojosefson.com

Higher-order functions

• Takes a function as argument

map :: fn -> List -> List

``````user = {
name: String,
age: Int,
birthday: Date
}

users = [
{
name: "Fjodor",
age: 31,
birthday: "2009-04-21 14:25:29.5585588 UTC"
},
{
name: "Hugo",
age: 40,
birthday: "2010-04-21 14:25:29.5585588 UTC"
}
]

map :: (a -> b) -> List a -> List b
map (\a -> a.birthday) users``````

filter :: fn -> List -> List

``````user = {
name: String,
age: Int,
birthday: Date
}

users = [
{
name: "Fjodor",
age: 31,
birthday: "2009-04-21 14:25:29.5585588 UTC"
},
{
name: "Hugo",
age: 40,
birthday: "2010-04-21 14:25:29.5585588 UTC"
}
]

filter :: (a -> Bool) -> List a -> List a
filter (\ x -> x.age `mod` 2 == 0) users``````

Currying

• A function is applied to its arguments one at a time

• Each application returns a new function that accepts the next argument

``````function add(a, b) {
return a + b;
};

//Normal add function takes two arguments
node> const age = add(1, 3);
4

``````

Curried

``````//What is Albins age?
//Albin is half the age of Hugo which is three years older than me

const add = a => b => a + b;

//Curried div
const div = b => a => a / b;

const myAge = 32;

const halfTheAge = div(2);

const albinsAge = halfTheAge(threeYearsOlder(myAge))
17.5

//OR by using function composition
node> const R = require('ramda');

node> const findOutAlbinsAgeBasedOnMine = R.compose(halfTheAge, threeYearsOlder);
node> const albinsAge = findoutAlbinsAgeBasedOnMine(myAge)
17.5
``````

Recursion

``````node> const listOfNumbers = [ 1, 2, 3, 4, 5, 6, 7, 8 ];

node> [ head, ...tail ] = listOfNumbers;

1

node> tail
[ 2, 3, 4, 5, 6, 7, 8 ]``````

Recursive dinner

``````const dinnerName = (acc, ingredientList) => {
if (!ingredientList.length) {               // Exit condition
return acc;
}
const [head, ...tail] = ingredientList;     // Destructuring
return dinnerName(head + acc, tail);        // Recursion
};

node> const ingredients = [ 'soup', 'mushroom', 'forest' ];

node> const dinner = dinnerName('', ingredients);

node> dinner;
'forestmushroomsoup'``````

Exercise

create a recursive function that takes a list of numbers

and returns only even numbers

(hint find the modulo operator)

Pure functions

• Idempotent
• Does not cause side-effects

Idempotency

Always evaluates the same result value

given the same argument values

``````// Idempotency requires your function to always return the same result
// given the same argument no matter how many times you invoke it

node> const R = require('ramda');

node> const composedIdentity = R.compose(R.identity, R.identity);

// OR

node> composedIdentity(32) === R.identity(32)
true``````

non-idempotent example

``````// NON-IDEMPOTENT
const nonIdempotentFn = arg => {
return arg.length;
};

node> nonIdempotentFn('hello');
5

node> nonIdempotentFn(nonIdempotentFn('hello'));
undefined

node> nonIdempotentFn(5)
undefined

``````

Side-effects

• modifies state.
• interacts with functions.
• interacts with the outside world.

By Hugo Josefson

Practical Functional Programming - An intro

Introduction for how all programmers can benefit from a little functional programming (fp) in their daily work.

• 1,689