functional javascript, cvjs

Post on 12-May-2015

660 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

Javascript Meetup in Charlottesville for CVjs. http://www.meetup.com/Central-Virginia-Javascript-Enthusiasts-CVJSE/events/132911552/

TRANSCRIPT

Talk Functional Javascript!

//+ CV.js :: September 18th, 2013

Kevin Welcher

Shout Out

Shout Out

Something about Camp?

10k Feet

• [Underscore.js / Lodash.js]

• Functional Concepts

• Composition

• Currying

• [Demo]

Underscore.jsLodash.js

Highlights

• reduce

• map

• pluck

• filter

• find

reduce

• The grandaddy, most iterators can be made out of reduce

• “Reduce a list to a new object”

map

• Bread and butter iterator

• Used to transform a list of elements from one type to another

• Whatever is returned within the iterator is the new object

pluck

• Iterates over a list of objects and returns a new list made of the specified property from each object

• A common use for map

• IE: plucking the name from an array of people objects

filter

• Only allows values that pass a predicate into the new list

• As with all these methods, it returns copies of the data

find

• Accepts a predicate and returns the first item that passes the predicate

Much, much more...• Many predicates

(isArray, isNull, ...)

• keys / values

• groupBy

• result

• array methods

• union / intersection

• chain / compose

• extend / defaults

• simple templates

• pick / omit

FP vs OO

• The language of the... language

• How complexity is hidden

• How data is stored

Functional Concepts

Function purity

• Deterministic

• Does not depend on external state

• Does not depend on IO

• Does not cause side effects

Function purityvar View = Backbone.View.extend({ initialize: function() { this.generateList(); }, generateList: function() { this.list = new Backbone.Collection([ {name: 'sally'}, {name: 'joe'} ]); }});

Function purityvar View = Backbone.View.extend({ initialize: function() { this.list = this.generateList(); }, generateList: function() { return new Backbone.Collection([ {name: 'sally'}, {name: 'joe'} ]); }});

Functions as data

• First class citizens

• Identified by their returns

• Modifiable

Functions as building blocks

Functions which consume the return value of the function that follows.

Composition:

Functions as building blocks

a() b() c()

a(b(c(x))) === compose(a, b, c)(x)

Composition

Functions as building blocks

function add1 (x) { return x + 1;}

var add3 = compose(add1, add1, add1);

add3(0);

//> 3

Functions as building blocks

function add1 (x) { return x + 1;}

var add3 = compose(add1, add1, add1);

add3(0);

//> 3

0

Functions as building blocks

function add1 (x) { return x + 1;}

var add3 = compose(add1, add1, add1);

add3(0);

//> 3

01

Functions as building blocks

function add1 (x) { return x + 1;}

var add3 = compose(add1, add1, add1);

add3(0);

//> 3

012

Functions as building blocks

function add1 (x) { return x + 1;}

var add3 = compose(add1, add1, add1);

add3(0);

//> 3

0123

Functions as building blocks

function not (x) { return !x;}

var boolify = compose(not, not);

not(not({}));boolify({});

//> true

Functions as building blocks

function addTitle (x) { return ‘Mr. ‘ + x;}

function addSalutation (x) { return ‘G’day, ‘ + x;}

var meetAndGreet = compose(addSalutation, addTitle);

addSalutation(addTitle('Baggins'));meetAndGreet('Baggins');

//> G’day, Mr. Baggins

Functions as building blocks

function add (x, y) { return x + y;}

var add1 = compose(???);

//> profit

Currying

“Taking a function that takes multiple arguments and transforming it to a chain of functions that accept a single

argument.” - Wikipedia

Notation

//+ <method name> :: type -> type -> type

Notation

//+ <method name> :: type -> type -> type

A function that take takes an argument and returns a value of type

Notation

//+ <method name> :: type -> type -> type

A function that take takes an argument and returns a value of type

integer -> integer

A function that takes in a single argument of type integer

The return type of integer. Since nothing follows, it is the final return

Notation

//+ <method name> :: type -> type -> type

A function that take takes an argument and returns a value of type

Notation

//+ <method name> :: type -> type -> type

The ultimate return value of a function

//+ not :: a -> boolean

function not (x) { return !x;}

not(true) //> false

//+ not :: a -> boolean

function not (x) { return !x;}

not(true) //> false

The a (or any other lower case letter) means we don’t care about the type.

//+ add :: a, a -> a function add(x, y) { return x + y;}

add(1, 2); //> 3

//+ add :: a, a -> a function add(x, y) { return x + y;}

add(1, 2); //> 3

I am abusing notation :(

“Taking a function that takes multiple arguments and transforming it to a chain of functions that accept a single

argument.” - Wikipedia

//+ add :: a, a -> a

//+ add :: a -> a -> a

//+ add :: a -> a -> a

function add(x) { return function (y) { return x + y; };}

add(1)(2); //> 3

ed

//+ add :: a -> a -> a

function add(x) { return function (y) { return x + y; };}

add(1)(2); //> 3

ed

//+ add :: a -> a -> a

//+ add :: 1 -> a -> a

//+ add1 :: integer -> integervar add1 = add(1);

add1(2); //> 3

//+ add :: a -> a -> a

//+ add :: ‘Mr. ‘ -> a -> a //+ addTitle :: string -> stringvar addTitle = add('Mr. ');

addTitle('Baggins');//> Mr. Baggins

Problem

That _ is ugly

//+ add :: a -> a -> a

function add(x) { return function (y) { return x + y; };}

add(1)(2); //> 3

autoCurry

A custom function that automatically curries for you.

For each parameter of a function, it returns a new function.

That _ is ugly

//+ add :: a -> a -> a

var add = function(x, y) { return x + y;}.autoCurry();

add(1, 2); //> 3add(1)(2); //> 3 Awww yissss

Cool Story Bru...

Let Me Convince You With...

More Examples!

reduce

//+ reduce :: fn -> a -> array -> avar reduce = function (fn, start, list) { // ... }.autoCurry();

reduce

//+ reduce :: fn -> a -> array -> avar reduce = function (fn, start, list) { // ... }.autoCurry();

function (cnrt, val, index, list) { // ...}

Sum all the numbers in a list?

var items = [1, 2, 3];

//+ reduce :: fn -> a -> array -> areduce(function (crnt, val, index, list) { return crnt + val;}, 0, items);

//> 6

var items = [1, 2, 3];

//+ reduce :: fn -> a -> array -> areduce(function (crnt, val, index, list) { return crnt + val;}, 0, items);

//> 6

We don’t use these two arguments so we can omit them

var items = [1, 2, 3];

//+ reduce :: fn -> a -> array -> areduce(function (crnt, val) { return crnt + val;}, 0, items);

//> 6

var items = [1, 2, 3];

//+ reduce :: fn -> a -> array -> areduce(function (crnt, val) { return crnt + val;}, 0, items);

//> 6

This function looks familiar...

//+ add :: a -> a -> a

var add = function(x, y) { return x + y;}.autoCurry();

var items = [1, 2, 3];

//+ reduce :: fn -> a -> array -> areduce(function (x, y) { return x + y;}, 0, items);

//> 6

var items = [1, 2, 3];

//+ reduce :: fn -> a -> array -> areduce(function (x, y) { return x + y;}, 0, items);

//> 6 Instead of inlining the function, just pass

the function’s pointer

var items = [1, 2, 3];

//+ reduce :: fn -> a -> array -> areduce(add, 0, items);

//> 6

var items = [1, 2, 3];

//+ reduce :: fn -> a -> array -> areduce(add, 0, items);

//> 6

Cool! But isn’t reduce curried? Can we make this into a generic function?

var items = [1, 2, 3];

//+ reduce :: add -> 0 -> array -> a//+ sum :: array -> integervar sum = reduce(add, 0);

sum(items);//> 6

Demo

https://gist.github.com/kaw2k/6312261

Lessons Learned?

Keep your methods short and to the point

It is easier to build things if your building blocks are small

Stick your data as the last parameter

reduce = function (fn, starting value, data)

function (general, ..., specific)

Optional parameters are hard

Make a general function and curry it to take optional stuff

Functional purity is pretty cool

• Easier to maintain

• Easier to reason

• Easier to test

• Easier to transport

Obligatory Marketing

(We are hiring)

top related