functional-js-wut



functional-js-wut

0 0


functional-js-wut

A deck for Develop Denver

On Github killtheliterate / functional-js-wut

Functional JavaScript. Wut?

In which I expound on things that are interesting to me.

Garrett Dawson

@killtheliterate

I've been a front-end dev of 5 years. I work at VictorOps

I started in Drupal, accidentally became a PHP developer.

I Decided to refocus on JS, and have been learning a lot by studying FP

I'm a beginner. I hope I always will be.

What Is Functional Programming?

It is a programming style that "...produces abstraction through clever ways of combining functions" [1]

What is abstraction? It's a less verbose way of describing the solution to a problem

Why is abstraction good? It allows us to write more generalized solutions. DRY

At it's core, the function is an abstraction. It encapsulates some operation we would like to do over and over

What Is Functional Programming?

How is abstraction produced using this style of programming?

By Leveraging first class functions and higher-order functions

...also, by pretty much hating global state

Straight-up. So, we'll need a functional language, then.

To Functionally Program, You Need A Functional Language

  • FP needs to be facilitated by language features
  • Some languages are strictly functional - Haskell
  • Some languages are functional without strict enforcement - Scala

Obviously, the things we've talked about need to be facilitated by the programming language

Some languages are purely functional, others are a mash-up

I'll be using JavaScript as the language of example

FP is such a good idea, many languages incorporate things like lambdas

First Class Functions

First class functions are values, and can be used in every way that typical expressions can

They are values. The benefit from all the advantages of being values. Code = data

Assignment, return, argument, etc.

First Class Functions

Can be assigned to variables

          
            var foo = function() {return 'hai'};

            foo(); // "hai"
          
        

You can see here that we are assigning a function to a variable.

This is the essence of "lambdas"

Note that it's not the return value of the function that is assigned, but the function itself.

Expression vs. declaration. Declarations are basically destructured to expressions

First Class Functions

Can be returned by functions

          
            var bar = function() {
              return function() {return 'hai'};
            };

            bar(); // function () {return 'hai'}
          
        

Note that we assign a function to the variable bar

And when we call the function referenced by bar, we get another function

First Class Functions

Can be passed as arguments to other functions

          
            var baz = function(func) {
              return func();
            };

            baz(function() {return 'hai'}) // "hai"
          
        

Here, we add a function to our argument list. It gets fired off from the original function, since it's been aliased to func

Probably looks a bit familiar. Like a callback in an event handler

Higher-Order Functions

Use functions as its parameters and/or return a function

          
            var bar = function(func) {
              return function() {
                return func();
              };
            };

            bar(function() {return 'hai'})() // "hai"
          
        

Functions that operate on functions

Notice the immediate function invocation at the end

Why Functionally Program with JavaScript?

Why functionally program? And why do it with JavaScript?

I'll go over some of the motivations to learn the functional aspects of JS

FP is a Language Feature

  • JS has first class functions (and anonymous function expressions)
  • JS has higher-order functions
  • JS has closures (we'll talk about this later)

First, lets check that JS meets our criteria for FP

Since FP is core to JS, you need to know it to be good at JS

Turns out, it's one of the best features of JavaScript

Functional JS Makes Your Programs Better

  • Encourages small units of code
  • Is easier to reason about
  • Is DRY (do not repeat yourself)

Small functions are testable

Small functions are single responsibility, less cognitive load

Well encapsulated code is elegant

FP Concepts Transfers To Other Languages

it's a style, not a syntax

  • Haskell
  • Erlang
  • Scala
  • Clojure
  • Uh... math

It gives you a powerful paradigm that may lead you elsewhere

Alright, Okay, Alright

How, functional JavaScript?

We meet our criteria, let's see some examples

These "techniques" are built of one another

First, A Review

We know:

  • What function expressions are
  • What higher-order functions are

With first class functions, suddenly you have a lot of tricks you can pull off

I'll talk about some of those tricks, why they're useful.

Stateless functions

Stateful functions mutate state outside of their scope. FP avoids mutation.

          
            var number = 1; // This is NOT functional programming

            var increment = function() {
                return number += 1;
            };

            increment(); // 2
            increment(); // 3
            increment(); // 4
          

          * Stephen Young [2]
        

First up, let's talk about how state is dealt with in FP

  • What is state? It's simply the state of our program. What we're doing, what we're messing with
  • What todo have I selected? What page am I editing?
  • State, at root, is stored in containers (variables)
  • How does FP avoid mutating state?

Stateless Functions

Stateless functions don't mutate state outside their scope

          
            var number = 1;

            var increment = function(n) {
                return n + 1;
            };

            increment(number); // 2
            increment(number); // 2
            increment(number); // 2
          

          * Stephen Young [2]
        

Async!

This function looks almost the same as before, except this time we're passing an argument

We want a function to always give the same value back.

We can build pipelines this way

Mutating shared states can have unexpected consequences

Shared state makes async programming hard. Maybe impossible

Use Recursion For Looping

To understand recursion, you must understand recursion.

*Anonymous

So, if we're stateless, how do we loop?

One way is to leverage recursion

Use Recursion For Looping

Functions that call themselves

          
            var loop = function(n) {
                if (n > 9) {
                    console.log(n);
                    return;
                } else {
                    console.log(n);
                    loop(n + 1);
                }
            };

            loop(0);
          

          * Stephen Young [2]
        

Notice that we're not using a for or while loop, because they are stateful

  • Can be stateless
  • Can be memoized
  • Caveat: Have a call stack limitations
  • So: Can be trampolined

Use Array.prototype#Methods

Applicative programming is a technique that allows a function to be applied to each element of a list

*Mary Simoni [3]

More looping!

Looping on lists is crucial

Use Array.prototype#Methods

Array.prototype.map()

          
            var squared = [1, 2, 3, 4, 5].map(function(el) {
              return Math.pow(el, 2);
            }); // [1, 4, 9, 16, 25]
          
        

Projection

We're not mutating the array. We're storing our return in a new bucket.

Use Array.prototype#Methods

Array.prototype.filter()

          
            var even = [1, 2, 3, 4, 5].filter(function(el) {
              return el % 2 === 0;
            }); // [2, 4]
          
        

Use Array.prototype#Methods

Array.prototype.reduce()

          
            var sum = [1, 2, 3, 4, 5].reduce(function(memo, curr) {
              return memo + curr;
            }); // 15
          
        

Projection

Tricks like algebraic logic. Can reduce to true/false.

Can reduce a list to another type. Array to Object

Build Predicate Functions

A predicate determines whether or not something is true or false.

Build Predicate Functions

          
            var isNull = function(obj) {
                return obj === null;
            };

            isNull(null) // true
          
        

Array.prototype.filter() could use a predicate.

Use Closures

Closures are functions that refer to independent (free) variables... the function defined in the closure "remembers" the environment in which it was created.

*Person that wrote the MDN page[5]

Use Closures

          
            function stringCount(string) {
              return function(subString) {
                return string.match(new RegExp(subString, 'g')).length;
              };
            }

            var count = stringCount('sup sup sup');

            count('sup'); // 3
          
        

Closures are much easier than they are made out to be, because a lot of folks are introduced to them in the wrong way.

Function context (call-site) and lexical scope (variable lookup) are why JS has closures.

Closures are why we can curry functions in JS.

Build Curried Functions

Currying is the act of taking a function that takes more than one argument and converting it to an equivalent function taking one argument.

*Reginald Braithwaite [3]

Build Curried Functions

          
            var foo = function (x) {
               return function (y) {
                 return function (z) {
                   return x + y + z;
                 }
               }
             }

             var bar = foo(1) // partially applied function
             bar(2)(3) // 6
          
        
  • Functions made up of unary functions
  • Functions that wait to yield a value until all arguments are passed
  • In other words, a variadic function made of nested unary functions
  • Can be approximated using Function.prototype.bind()

Compose Functions With Functions

It’s really that simple: Whenever you are chaining two or more functions together, you’re composing them

*Reginald Braithwaite [4]

Compose Functions With Functions

          
            var compose = function(a, b) {
              return function (c) {
                return a(b(c));
              };
            };

            var addOne = function(number) { return number + 1 };
            var double = function(number) { return number * 2 };
            var addOneAndDouble = compose(double, addOne); // right to left

            addOneAndDouble(2); // 6
          
        

This is one of my favorites. Notice it's leveraging partial application.

This ties into the idea of DRY. Make symbol, general purpose functions that you combine into more complex or specific functions.

ez Mode

(AKA Easy Mode)

Don't need libraries, but because FP is made up of many common idioms, it's nice to not have to write them.

Underscore/Lo-Dash

          
            var numbers = _.filter([1, 'foo', 3, 'bar', 5, 6], _.isNumber); // [1, 3, 5, 6]

            var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) {
              return num % 2 == 0;
            }); // [2, 4, 6]
          
        

RTFM. The underscore annotated source is SOOOOOO good

Ramda

          
            var evens = ramda.filter(function(num){ return num % 2 === 0; });
            evens([1, 2, 3, 4, 5, 6]); // [2, 4, 6]
          
        

And More Things

There is a lot to know about FP

  • Functors
  • Monads! (value burritos, mmm)
  • Promises (an monad)
  • Combinators

Go forth and write better JavaScript.

0