Functional Programming

From bibbleWiki
Jump to navigation Jump to search

Introduction

This page is meant to give an overview of terms associated with functional programming and used with other languages like scala, kotlin, javascript.

Notation

Getting Started

The important thing is that the x on the LHS is a placeholder for the RHS and not a multiplier of the function.

Given
y = x²+x f(x) = x² + x // We name it to f(x) for shorthand
y = 8x-5 g(x) = 8x - 5 // We name it to g(x) for shorthand

Now to evaluate
f(4)
We replace the x on the RHS
f(4) = (4)² + 4 = 20 
g(4) = 8(4) - 5 = 27

And
f(x-3)
We replace the x on the RHS
f(x-3) = (x-3)² + (x-3)
       = (x-3)(x-3) + (x-3)
       = x² -3x -3x + 9 + x -3
       = x² - 5x + 6

Composite Fucntions

Getting Started

When we combine functions we use the open circle and it is pronounced as "of". So given

f(x) = 3x - 4
g(x) = x² -3

gºf = f[g(x)]   // Does not mean multiply and is pronounced "g" of "f"
    = f(x² -3)  // Repalce g(x) with x² -3 i.e. g(x)
    = 3(x² -3 ) -4
    = 3x² -9 -4
    = 3x² -13
  
// Lets find fºg
                   // Hard to follow first
fºg = g(3x -4)     // or g(x) where x is 3x -4
    = (3x -4)² - 3 // Hard to follow first time but g(x) = x² -3
                   // In our case x = (3x -4) above 
    = 9x² - 12x - 12x + 16 - 3
     = 9x² - 24x + 13

Second Example

f(x) = 5x + 2
g(x) = x³ - 4

Evaluating f[g(2)]

So
g(2) = 2³ -4 = 4

Therefore
 
f[g(2)] = f[4]
        = 5(4) + 2 // using f(x)
        = 22

Evaluating g[f(-1)]

So 
f(-1) = 5(-1) + 2 
      = -3

Therefore

g[-3] = (-3)³ -4  // from g(x)
      = -27 -4 
      = =31

Reason for this Page

The reason this page exists it the example

const twice = (f, v) => f(f(v))
const add3 = v => v + 3
twice(add3, 7) // 13

I found it really hard to understand the notation f(f(v)) which actually means as the name implies call f(v) and then call f(v) with the result of the first call.

const twice = (f, v) => { //v=7
  v = f(v); //v=10
  v = f(v); //v=13
  return v;
}

Pure Functions

Introduction

  • They will always produce the same answer with the same input.
  • They will not produce side effects
function plus(a, b) {
  return a + b;
}

Impure and Side Effect

Given

let str = "some thing"

let f_pure = function(_input) {
  let _output = _input.toUpperCase()
  return _output
}

let f_impure = function(_input) {
  let _output = _input.toUpperCase()
  str = _output
  return _output
}

The f_pure will return what was passed in and modify no other data. However the f_impure does modify str outside of the scope of the function (side effect) and therefore is not considered to be a pure function.

Statics vs Pure

The difference between static and pure functions is that a static can be a void and can increment other static values.

Advantages

The methods are easier to maintain
They are easier to maintain because a developer needs to spend less time analyzing the impacts of changes to the method. The developer does not have to consider the state of other inputs that are used in the method. When considering a change to a method that is not a pure function, the developer must think about the impact on properties used in the method that were not passed in.
The methods are easier to test
When writing a unit test, it is easy to pass values into the method and write the test to verify the correct output. But writing tests on methods that are not pure functions take longer and are more complicated because more setup or injection of values is necessary for the test. The methods are easier to re-use. You can call the method from other places in the module, or call the method from several different modules easily when the method is a pure function.
The methods are easier to move to other classes.
If you have a pure function in one class and you want to move it to a utility class to be used by other modules, it is easy to do so.
The methods are more likely to be thread-safe
Pure functions don’t reference variables in shared memory that are being referenced by other threads. Caveat: variables such as objects that are passed by reference could still experience threading problems when used inside of static methods that are pure functions.

Higher Order Functions

Introduction

Higher-order functions are functions which

  • accept functions as parameters
  • or returns a function
function multiplier(factor) {
    return (x) => {
        return x * factor
    }
}

// Create two instances 
let doubler = multiplier(2)
let tripler = multiplier(3)

doubler(4)
>8

tripler(4)
>12

Examples in JavaScript

In Javascript we have functions like

  • filter
  • map
  • reduce
  • sort

These are all higher order functions because we pass a function to them and they return a function back

Given the following we can use the filter function to improve the code.

var dogs = []

var animals = [
  {name: 'Fluffykins', species: 'rabbit'},
  {name: 'Caro',       species: 'dog'},
  {name: 'Hamilton',   species: 'dog'},
  {name: 'Jimmy',      species: 'cat'},
]

for(var i = 0; i < animals.length; i++) {
   if(animals[i] === 'dog')
      dogs.push(animals[i]
}

// Filter version #1
let myFunc = function(animal) {
   return animal.species === 'dog'
}

var dogs = animals.filter(myFunc)

// Filter version #2
var dogs = animails.filter((animal) => {
   return animal.species === 'dog'
})

We can see that filter takes a function as an argument and returns a result.