Functional Programming

(Using Python)

Software Engineer at Pesto Tech

@salman_arfat

 

Presented at PyDelhi

Life is too short for imperative programming

-- John Hughes (One of the designers of Haskell)

A little bit of History!

Main Programming Paradigms

A paradigm describes distinct concepts or thought patterns some scientific discipline.

  • Imperative Programming
  • Functional Programming
  • Logic Programming
  • Object Oriented Programming

Imperative programming 

  • modifying mutable variables
  • using assignments
  • and control structures such as if-else, loops, break, continue, return

uses statements that change a program's state.

The most common way (informal) way to understand imperative programs is as instruction sequences to a von Neumann Computer

Given a numeric string, get the next character that comes after it.

There's a strong correspondence between

  • Mutable variables ≈ memory cells
  • Variable dereferences ≈ load instructions
  • Variable Assignments ≈ Store instructions
  • Control Structures ≈ Jumps

Problem: How can we avoid conceptualising programs words by word?

Functional Programming

treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data.

It's a paradigm of programming where fundamental operation is the application of functions to arguments.

  • In restricted sense, FP is programming without mutable variables, assignments, loops, and other imperative control structures
  • In a wider sense, focusing on functions
  • Functions are values that can be produced, consumed, and composed.

Example: QuickSort

class QuickSort 
{ 
    int partition(int arr[], int low, int high) 
    { 
        int pivot = arr[high];  
        int i = (low-1); // index of smaller element 
        for (int j=low; j<high; j++) 
        { 
            if (arr[j] <= pivot) 
            { 
                i++; 
  
                int temp = arr[i]; 
                arr[i] = arr[j]; 
                arr[j] = temp; 
            } 
        } 
  
        int temp = arr[i+1]; 
        arr[i+1] = arr[high]; 
        arr[high] = temp; 
  
        return i+1; 
    } 
  
    void sort(int arr[], int low, int high) 
    { 
        if (low < high) 
        { 
            int pi = partition(arr, low, high); 
            sort(arr, low, pi-1); 
            sort(arr, pi+1, high); 
        } 
    }
} 

FP combines the flexibility and power of abstract mathematics with the intuitive clarity of abstract mathematics.

-- xkcd

Why is it Useful?

There are many possible answers to this question, but generally speaking:

  • The abstract nature of functional programming leads to considerably simpler programs;
  • It also supports a number of powerful new ways to structure and reason about programs.
total = 0;
for (i = 1; i <= 10; ++i)
   total = total+i;
sum [1..10]

What is a function?

A function is a 

  • relation

  • between input values 

  • to output values

Functional Programs have

  • Pure Functions
  • Immutability
  • No Side effects
  • First Class Functions
  • Higher Order Functions
  • Function Composition
  • and much more ...

Side Effects

A side effect is any application state change that is observable outside the called function other than its return value. Side effects include:

  • Modifying any external variable or object property (e.g., a global variable, or a variable in the parent function scope chain)
  • Logging to the console
  • Writing to the screen
  • Writing to a file
  • Writing to the network
  • Triggering any external process
  • Calling any other functions with side-effects

Stateless programs

  • Idempotent (pure) functions
  • Order of evaluation not defined
  • Lazy evaluation possible
  • Optimizations
  • Concurrent processing
  • Easier to test and debug
  • Side effects can’t be eliminated, but can be isolated

Higher Order Functions

A function is called higher-order if it takes a function as an argument or returns a function as a result.

The Map Function

The higher-order library function called map applies a function to every element of a list.

map :: (a -> b) -> [a] -> [b]
> map (+1) [1,3,5,7]

[2,4,6,8]

Reduce

def nextCharFromNumberString(numStr):
    trimmed = numStr.strip()
    number = int(trimmed)
    number = number + 1
    return chr(number)

result = nextCharFromNumberString('   64    ')
print(result)
def nextCharFromNumberString2(numStr):
    return map(
        chr,
        map(
            lambda num: num + 1,
            map(
                lambda stripped: int(stripped), 
                map(
                    lambda string: string.strip(), 
                    [numStr]
                )
            )
        )
    )

Example

  • We have a dict of colors with their hex values.
  • We want to remove the hash sign 
  • and turn the string to uppercase.
def findColor(name):
    colors = {
        'red': '#ff4444', 
        'blue': '#3b5998', 
        'yellow': '#fff68f'
    }
    return colors.get(name)

Left or Right

Either = Right || Left

Enforce a null check with composable code branching using Either

Either doesn't actually come into play. It will just refer to one of these two types.

Usually, we don't know if we have a Right or a Left. We don't know which one it is.

class Left:
    def __init__(self, x):
        self.x = x
    def map(self, f):
        return Left(self.x)
    def fold(self, f, _):
        return f(self.x)
    def __str__(self):
        return 'Left(%s)' % self.x


class Right:
    def __init__(self, x):
        self.x = x
    def map(self, f):
        return Right(f(self.x))
    def fold(self, _, g):
        return g(self.x)
    def __str__(self):
        return 'Right(%s)' % self.x

Functional Programming in Python

By Arfat Salman

Functional Programming in Python

  • 394