Some thoughts about functional programming

$ whoami
Erik Wallin
Consultant at DevCode
@c01ac0ca

Programming paradigms

Paradigm = Style (characteristics, concepts, thought patterns)

  • Imperative
  • Functional
  • Logic
  • Object Oriented

Logic programming

  • Expressing facts and rules about some problem domain.
  • Prolog
  • https://bernardopires.com/2013/10/try-logic-programming-a-gentle-introduction-to-prolog/

Object oriented programming

  • Objects with data and methods
  • Encapsulation
  • Polymorphism
  • Message passing
  • Etc

Imperative programming

  • Modify mutable variables
  • Control flows (if/else, loops, break, continue, return)
  • Tell the machine how to do something
  • Opposite: Declarative programming (Tell the machine what you would like to happen)
  • Typical program
    •  cmd1; cmd2; cmd3; cmd4;

Functional programming

  • Roots in lambda calculus
  • No mutable variables
  • No loops or break/continue/return
  • Functions are "first-class citizens"
  • Referentially transparent functions
  • Typical program (or at least parts) with composition
    • fn1(fn2(fn3(fn4, x, y)))
  • "Pure" functional programming don't have side effects, i.e. updating state, print things on screen, etc

Functions are "first-class citizens"

  • Functions defined everywhere, e.g. inside other functions
  • Can be passed around as arguments to other functions
  • Currying
    • Methods may define multiple parameter lists. When a method is called with a fewer number of parameter lists, then this will yield a function taking the missing parameter lists as its arguments.

Referentially transparent functions

  • An expression is said to be referentially transparent if it can be replaced with its value without changing the behaviour of a program
  • ​Same input gives same output
  • def plusone(x: Int): Int = x+1

Pure functional programming

  • Programming without side effects (???)

  • Don't mention the M-word!

- Vet du vad en Monad är? /erwa

- Jag vet vad en månad är. /joho

Links

  • https://www.coursera.org/course/progfun
  • https://www.coursera.org/course/reactive

Style vs language

A language can encourage a paradigm, but seldom decide completely 

Functional languages

  • Lisp
  • Haskell
  • XSLT
  • XPath

Encouraging languages

  • Scala
  • F#

Functional programming in java

Combining functional and imperative programming

  • Solve the business problems, discuss different solutions, be pragmatic
  • See functional programming as a good tool in your toolbox

 

From xkcd

In the deepest scala library code we find a lot of imperative code

//List.scala

sealed abstract class List[+A] ...

  override def drop(n: Int): List[A] = {
    var these = this
    var count = n
    while (!these.isEmpty && count > 0) {
      these = these.tail
      count -= 1
    }
    these
  }

...

Show us some code!

No mutable variables

// This is very strange for a mathematician
var x = x + 1

// Do instead
val y = x + 1

No loops or imperative control structures

// Imperative
def gcd(x: Int, y: Int): Int = {
    var a = x
    var b = y
    while (a != b) {
        if (a > b) {
            a = a − b
        } else {
            b = b − a
        }
    }
    return a;
}

// Functional way with recursion
def gcd(a: Int, b: Int): Int =
    if (b == 0)
        a
    else
        gcd(b, a % b)

Functions are first-class citiens


def id(x: Int): Int = x
def square(x: Int): Int = x * x
def powerOfTwo(x: Int): Int = if (x == 0) 1 else 2 * powerOfTwo(x - 1)

def sum(f: Int => Int, a: Int, b: Int): Int = f(a) + f(b)

//Composition
def sumInts(a: Int, b: Int): Int = sum(id, a, b)
def sumSquares(a: Int, b: Int): Int = sum(square, a, b)
def sumPowersOfTwo(a: Int, b: Int): Int = sum(powerOfTwo, a, b)


println("sum squares 2 and 4 = " + sumSquares(2, 4))

Lambda expressions

Anonymous functions

def sum(f: Int => Int, a: Int, b: Int): Int = f(a) + f(b)


println("sum quadruples 2 and 4 = " + sum(x => x * 4, 2, 4))

Closure

Function that uses variables declared outside of the function.

var factor = 3
val multiplier = i => i * factor

println("muliplier(1) value = " +  multiplier(1))
println("muliplier(2) value = " +  multiplier(2))

Currying

def modN(n: Int)(x: Int) = ((x % n) == 0)

def mod13 = modN(13)

println("modN(13, 8) value = " +  modN(13, 8))
println("mod13(8) value = " + mod13(8))

Working with collections

If a java programmer should remember anything from this presentation this is it!

// Example from Oracle

// Imperative
List<Transaction> groceryTransactions = new Arraylist<>();
for (Transaction t: transactions) {
  if(t.getType() == Transaction.GROCERY) {
    groceryTransactions.add(t);
  }
}
Collections.sort(groceryTransactions, new Comparator() {
  public int compare(Transaction t1, Transaction t2) {
    return t2.getValue().compareTo(t1.getValue());
  }
});
List<Integer> transactionIds = new ArrayList<>();
for(Transaction t: groceryTransactions) {
  transactionsIds.add(t.getId());
}

// Declarative/Functional way
List<Integer> transactionsIds = 
  transactions.stream()
    .filter(t -> t.getType() == Transaction.GROCERY)
    .sorted(Comparator.comparing(Transaction::getValue).reversed())
    .map(Transaction::getId)
    .collect(toList());

Finally - Write clean code!

Single Abstract Method interfaces (SAM Interfaces) / Functional Interfaces 

// Don't write a Comparator as a anonymous inner class
Collections.sort(groceryTransactions, new Comparator() {
  public int compare(Transaction t1, Transaction t2) {
    return t2.getValue().compareTo(t1.getValue());
  }
});

// Use a lambda expression instead
Collections.sort(groceryTransactions,
  (Transaction t1, Transaction t2) -> t2.getValue().compareTo(t1.getValue());
);
Made with Slides.com