Program functionally, please

2013-03-12 00:00:00 +0000

Benefits

  • Higher abstractions
  • Concise code
  • Closer to the human mind
  • Easier to test

Functional programming principles

  • Immutability
  • No side effects
  • Functions are first class

First class functions

Functions as an argument

var server = net.createServer(function (socket) {
    socket.write('Echo server\r\n');
    socket.pipe(socket);
  });

First class functions

Functions as return values

var color = d3.scale.linear()
    .domain([-1, 0, 1])
    .range(["red", "white", "green"]);
  var c = color(1.1);

First class functions

You can use blocks in ruby

function in javascript

`A => B` type in scala

Immutability

  • Variables shouldn't mutate once they are set
  • Scala has two possible references: vars and vals
  • Reasignment to vals will generate a compile time error
  • -> embrace functional thinking

Functional thinking: collection manipulation

Please don't do this

function add1(arr) {
      for(i in arr) {
        arr[i] = arr[i]+1;
      }
      return arr;
    }

Functional thinking: collection manipulation

See why ?

> add1
    function add1(arr){
          for(i in arr) {
            arr[i] = arr[i]+1;
          }
          return arr;
        }
    > var l = [1,2,3,4];
    undefined
    > add1(l)
    [2, 3, 4, 5]
    > l
    [2, 3, 4, 5]

Functional thinking: collection manipulation

Try this

function add1(arr) {
      return arr.map(function(i) { return i+1; } );
    }
javascript arrays are functors

Functional thinking: collection manipulation

> add1
    function add1(arr) {
      return arr.map(function(i) { return i+1; } );
    }
    > var l = [1,2,3,4];
    undefined
    > add1(l)
    [2, 3, 4, 5]
    > l
    [1, 2, 3, 4]

Functional thinking: collection manipulation

scala> "Le nombre de lettre des mots uniques de cette phrase"
    .split(" ")
    .distinct
    .foldLeft(0)(_ + _.length)
  res1: Int = 41
  scala> "Une liste de mots de cette phrase regroupes par longueur"
    .split(" ")
    .groupBy(_.length)
  res2: scala.collection.immutable.Map[Int,Array[java.lang.String]] = Map(5 -> Array(liste, cette), 6 -> Array(phrase), 9 -> Array(regroupes), 2 -> Array(de, de), 3 -> Array(Une, par), 8 -> Array(longueur), 4 -> Array(mots))
  scala> res2.toList.sortBy(_._1)
  res3: List[(Int, Array[java.lang.String])] = List((2,Array(de, de)), (3,Array(Une, par)), (4,Array(mots)), (5,Array(liste, cette)), (6,Array(phrase)), (8,Array(longueur)), (9,Array(regroupes)))
  scala> res3.flatMap(_._2)
  res4: List[java.lang.String] = List(de, de, Une, par, mots, liste, cette, phrase, longueur, regroupes)

Branching functionally

Use recursion

scala> def factorial(i:Int):Int = {
      if( i > 0 ) {
        i*factorial(i-1)
      }
      else {
        1
      }
    }
    scala> factorial(12)
    res2: Int = 479001600
    
    scala> def fact(i:Int):Int = (1 to i).foldLeft(1)(_*_)
    fact: (i: Int)Int
    scala> fact(4)
    res4: Int = 24
Warning: recursion can lead to stackoverflow. You have to be wise and use tail recursion.

Functional collection manipulation in js

  • http://underscorejs.org/
  • http://eloquentjavascript.net/chapter6.html
  • https://github.com/mbostock/d3/wiki/Arrays

Advanced functional programming

  • Pattern matching
  • Tail call optimisation (scala @tailrec)
  • Lazy values and structures (infite streams / collections)
  • Partial functions, currying
  • DSLs

Functional patterns

Extremely cool functional projects

  • Datomic, the immutable database.
  • Chris Granger's LightTable: http://www.lighttable.com/
  • ClojureScript as a whole

Choose your weapon

  • Pure functional languages
    • Haskell
    • Clojure
  • Hybrid languages
    • Scala
    • Erlang
    • F#

Take aways

Learn a functional language