Functional Programming
with
JavaScript

JavaScript?

ES6+

 

Not quite what you run in your browsers

 

If anyone has issues understanding syntax, interrupt or ask!

Functional Programming?

Focus on functions and transformations instead of imperative steps

First Class Functions

Stateless

Pure Functions

Compatible with OOP

But like, why though?

Code gets

Clearer

 

Concise

 

Cleaner to refactor

This talk is titled Functional Programming

with JavaScript

First Class Functions

// Define functions on their own
const addOne = (x) => x + 1
const two = addOne(1)
const someNumbers = [1, 2, 3]

// Pass functions as arguments
const someBiggerNumbers = someNumbers.map(addOne)
// [2, 3, 4]

// Return functions from functions
const createAddFunction = (x) => {
  return (y) => y + x
}

const addUno = createAddFunction(1)

Stateless

// Error prone
 
const badProcessStudents = (students) => {
  addExtraCredit(students)
  curve(students)
  markFailing(students)
  return students
}

// Less error prone

const goodProcessStudents = (students) => {
  const ecStudents = addExtraCredit(students)
  const curvedStudents = curve(ecStudents)
  const pfStudents = markFailing(curvedStudents)
  return pfStudents
}

Stateless with Spread

const badUpdateGrade = (student) => {
  student.grade = 10
}

const goodUpdateGrade = (student) => {
  return {...student, grade: 10}
}

const badAddStudent = (students, student) => {
  students.push(student)
}

const goodAddStudent = (students, student) => {
  return [...students, student]
}

Pure Functions

// Don't do this!

const curve = 1.10
const badCurve = (students) => {
  for (student of students) {
    student.grade = student.grade * curve
  }
  return students
}


// Do this

const goodCurve = (students, curve) => {
  students.map(student => {
    return {...student, grade: student.grade * curve}
  })
}

Sometimes you
need more

Friendly Libraries

Immutable.js

Immutable

Cannot be changed after creation

 

Frees your mind from worrying about state

 

Enables lots of optimization techniques

Persistent

Allows for easy creation of updated objects

 

Relies on immutable data structures

 

Is actually fast

Immutable JS objects are both!

Immutable JS Basics

import Immutable from require('immutable');
var map1: Immutable.Map<string, number>;
map1 = Immutable.Map({a:1, b:2, c:3});
var map2 = map1.set('b', 50);
map1.get('b'); // 2
map2.get('b'); // 50

// This is potentially faster than the spread operator
// For sure less memory intensive

Immutable JS Justification

const students = [{name: "Kevin"}, {name: "Dan"}]
const gradedStudents = gradeStudents(students)

// What does gradedStudents look like?
// What does students look like?

const { List } = require('immutable')
const students = List([{name: "Kevin"}, {name: "Dan"}])
const gradedStudents = gradeStudents(students)

// What does gradedStudents look like?
// What does students look like?

Const (final, not immutable)

// Some people call this immutable

const students = [{name: "Kevin"}, {name: "Dan"}]

// But you can still do these things
students.push({name: "Cedric"})
students[0]["name"] = "K-Dog"

// You just can't do this

students = []

We have cooler data structures, now for cooler functions!

Ramda

Array.prototype is great!

Rambda is better

Rambda Basics

// Normal JS
const isUngraded = (task) => {
    return !task.graded
}

// Normal JS with Rambda
const isRambdaUngraded = R.whereEq({graded: false})

const ungradedTasks = tasks.filter(isUngraded)
const rambdaUngraded = R.filter(isUngraded, tasks)

// Honestly, the benefits aren't really clear... yet

Currying!

Currying

// Normal JS
const getUngradedTasks = (tasks) => {
  return tasks.filter(isUngraded)
}

// Rambda
const getRambdaUngradedTasks = R.filter(isUngraded) 

// No tasks?!?!

// That's currying!

Composability

Composability

const isGraded = R.whereEq({graded: true})
const hasZero = R.whereEq({grade: 0})
const isIncomplete = R.compose(isGraded, hasZero)
const getIncomplete = R.filter(isIncomplete)
const getParentEmail = R.pluck("parentEmail")
const getSadEmails = R.compose(getParentEmail, getIncomplete)

A Function for Everything

"But JavaScript is for visual things!"

FP on the Front End

Original Advocate

Data goes in, HTML comes out

Username Display

const StudentHeader = ({ username }) => {
  return <p>The logged in student is: {username}</p>
}

How do we manage all these stateless components?

They all can do this

You have to squint a bit and work hard with Ember

“I thought FP had to do with types?”

FP has to do with transformations

Types help you understand transformations

const gradedStudents = gradeStudents(students)

// What does gradedStudents look like?
// What does students look like?

const { List } = require('immutable')
const gradedStudents = gradeStudents(students)

// What does gradedStudents look like?
// What does students look like?

Enter

Basically, JS + Types

interface Student {
  name: string;
  graded: boolean;
  grade: number;
  parentEmail: string;
}

const kevin: Student = {
  name: "Kevin", 
  graded: true, 
  grade: 75, 
  parentEmail: "kevinsdad@hotmail.com"
}

const gradeStudents: (students: Student[]): Student[] => {
  ...
}

Great Editor Support

Defensive Coding

Lots more stuff!

  • Union Types
  • Type Aliases
  • Intersection Types
  • Type Guards
  • Decorators
  • (sometimes build issues)
  • and more!

But does it have monoids in the category of endofunctors?!?!

Enter Fantasyland

Fantasy Land gives you the tools to effectively describe all sorts of transformations

Honestly, wait until you're really curious before exploring more.
These tools are neat, but are NOT NECESSARY for functional programming and add a lot of JavaScript

Why limit yourself?

Transpilation!

Because compilation isn't a cool enough word

Text

Lots of options

Elm Example

import Html exposing (beginnerProgram, div, button, text)
import Html.Events exposing (onClick)


main =
  beginnerProgram { model = 0, view = view, update = update }


view model =
  div []
    [ button [ onClick Decrement ] [ text "-" ]
    , div [] [ text (toString model) ]
    , button [ onClick Increment ] [ text "+" ]
    ]


type Msg = Increment | Decrement


update msg model =
  case msg of
    Increment ->
      model + 1

    Decrement ->
      model - 1

ClojureScript Example

(ns example
  (:require [reagent.core :as r]))
(def click-count (r/atom 0))

(defn counting-component []
  [:div
   "The atom " [:code "click-count"] " has value: "
   @click-count ". "
   [:input {:type "button" :value "Click me!"
            :on-click #(swap! click-count inc)}]])

Before we end, chill

Functional Programming

  • Use functions that don't modify or depend on state
  • Chain functions to make complex processes
  • Focus on the transformation of items
  • Do not focus on the imperative steps

Thanks!

Questions?

Functional Programming with JavaScript

By Kevin Greene

Functional Programming with JavaScript

  • 319