learn you a functional javascript for great good
DESCRIPTION
We have been told by just about everyone that we should learning functional programming, let this session be your introduction using a language you already know JavaScript. Yep, JavaScript. No endless amounts of parentheses. No monadic arrows. Just good old JavaScript. We'll look take a look at the functional JavaScript landscape see how to use: Currying Combinators Multimethods We'll be using Underscore.js, allong.es, and bilby.js to help us.TRANSCRIPT
Learn You a Functional JavaScript for Great Good!Mike Harris
Functions!
Closures!
Currying!
Combinators!
Multimethods
Frameworks
> require("underscore");!{ [Function]! _: [Circular],! VERSION: '1.6.0',! …! map: [Function],! …! filter: [Function],! reject: [Function],!…! compose: [Function],! after: [Function],!…!}
> require("allong.es");!{ es: ! {!…! flip: [Function: unary],!…! curry: [Function: unary],! map: [Function: binary],! mapWith: [Function: binary],! mapArgumentsWith: [Function: binary],! filter: [Function: binary],! filterWith: [Function: binary],!…! allong: [Circular] }
> require("bilby");!{!…! curry: [Function: curry],! flip: [Function: flip],! identity: [Function: identity],! constant: [Function: constant],! compose: [Function: compose],!…! lens: [Function: lens],! isLens: [Function],! objectLens: [Function: objectLens],!…!}
Functions
nothing
function nothing(){};!!
nothing();!undefined
five
function five(){return 5;};!!
five();!5
makeFive
function makeFive(){! return function(){return 5;}!};!!makeFive();![Function]!var five = makeFive();!five();!5
fAdd
function five(){return 5;};!!
function fAdd(f, g){! return f() + g();!};!!
fAdd(five, five);!10
Closures
Closure
Function Environment
HelloMaker
hello greet
function helloMaker(){! var greet = "Hello";! return function(){return greet;};!};!!
var hello = helloMaker();! hello();!!
'Hello'
function helloMaker(){! var greet = "Hello";! return function(){return greet;};!};!!
var hello = helloMaker();! hello();!!
'Hello'
environmentfunction
Counter
get count
function counter(){! var count = 0;! return function(){return ++count;};!};!!
var ids = counter();!!
ids();!1!!
ids();!2
function counter(){! var count = 0;! return function(){return ++count;};!};!!
var ids = counter();!!
ids();!1!!
ids();!2
environmentfunction
Currying
f(a, b, c, d)g(b, c, d)
h(c, d)j(d)
f(a, b, c, d)
Curry
g(b, c, d)
Curry
h(c, d)C
urry
j(d)
ownAdd
f(a, b, c)
Curry
g(b, c)C
urry
h(c)
var ownAdd = function(a){! return function(b){! return function(c){! return a + b + c;! }! }!};!!
ownAdd(1)(2)(3);!6
var ownAdd = function(a){! return function(b){! return function(c){! return a + b + c;! }! }!};!!
ownAdd(1)(2)(3);!6
ownAdd
add1
g(b, c)
Curry
h(c)
var ownAdd = function(a){! return function(b){! return function(c){! return a + b + c;! }! }!};!!
var add1 = ownAdd(1);!add1(2)(3);!6
var ownAdd = function(a){! return function(b){! return function(c){! return a + b + c;! }! }!};!!
var add1 = ownAdd(1);!add1(2)(3);!6
add1a = 1
add3
h(c)
var ownAdd = function(a){! return function(b){! return function(c){! return a + b + c;! }! }!};!!
var add3 = ownAdd(1)(2);!add3(3);!6
var ownAdd = function(a){! return function(b){! return function(c){! return a + b + c;! }! }!};!!
var add3 = ownAdd(1)(2);!add3(3);!6
add3
a = 1b = 2
CombinatorsMoses Schönfinkel
andHaskell Curry
BluebirdB f g x = f (g x)
ComposeB f g x = f (g x)
Compose
Function Function Function
Compose
Function Function Function
Square and Add 1
x + 1 x * x
var compose = require(“underscore").compose;!!
var sqAnd1 = compose(! function(x){return x+1;},! function(x){return x*x;}!);!!
sqAnd1(2);!5
Guid
sha1 str counter
var compose = require("underscore").compose,! sha1 = require("node-sha1"),!!function counter(){! var count = 0;! return function(){return ++count;};!};!!function str(s){! return s ? s.toString() : "";!};!!var guid = compose(sha1, str, counter());!!guid();!'356a192b7913b04c54574d18c28d46e6395428ab'!guid();!'da4b9237bacccdf19c0760cab7aec4a8359010b0'
var! _ = require("underscore"),! compose = _.compose;
_.compose = function() {! var funcs = arguments;! return function() {! var args = arguments;! for (var i = funcs.length - 1; i >= 0; i--) {! args = [funcs[i].apply(this, args)];! }! return args[0];! };! };
Compose
Function Function Function
_.compose = function() {! var funcs = arguments;! return function() {! var args = arguments;! for (var i = funcs.length - 1; i >= 0; i--) {! args = [funcs[i].apply(this, args)];! }! return args[0];! };! };
CardinalC f x y = f y x
Flip / WithC f x y = f y x
FlipC f x y = f y x
flip
b a
var flip = require("bilby").flip;!!
function cat(s, t){return s + t;};!!
cat("Hello ", "Mike ");!'Hello Mike '!!
flip(cat)("Hello ")("Mike ");!'Mike Hello '
var flip = require("bilby").flip;!!
function cat(s, t){return s + t;};!!
var post = flip(cat);!!
var messageToMike = post("Mike ");!!
messageToMike("Hello ");!'Hello Mike '!!
messageToMike("Bye ");!'Bye Mike '
var! bilby = require("bilby"),! flip = bilby.flip;
function flip(f) {! return function(a) {! return function(b) {! return f(b, a);! };! };!}
flip
b a
function flip(f) {! return function(a) {! return function(b) {! return f(b, a);! };! };!}
WithC f x y = f y x
Filter_.filter = _.select = function(obj, predicate, context) { var results = []; if (obj == null) return results; if (nativeFilter && obj.filter === nativeFilter) return obj.filter(predicate, context); each(obj, function(value, index, list) { if (predicate.call(context, value, index, list)) results.push(value); }); return results; };
filter
array function
filter
1, 2, 3 isEven
var filter = require("underscore").filter;!!
function isEven(x){return x%2 === 0;};!isEven(2);!true!!
filter([1, 2, 3], isEven);![ 2 ]!!
[1, 2, 3].filter(isEven);![ 2 ]
var! _ = require("underscore"),! filter = _.filter;
_.filter = _.select = function(obj, predicate, context) {! var results = [];! if (obj == null) return results;! if (nativeFilter && obj.filter === nativeFilter) ! return obj.filter(predicate, context);! each(obj, function(value, index, list) {! if (predicate.call(context, value, index, list))! results.push(value);! });! return results;! };
filter
array function
_.filter = _.select = function(obj, predicate, context) {! var results = [];! if (obj == null) return results;! if (nativeFilter && obj.filter === nativeFilter) ! return obj.filter(predicate, context);! each(obj, function(value, index, list) {! if (predicate.call(context, value, index, list))! results.push(value);! });! return results;! };
FilterWithvar filter = binary( function filter (list, fn) { fn = functionalize(fn); return __filter.call(list, fn); }); var filterWith = flip(filter);
filterWith
arrayfunction
filterWith
1, 2, 3isEven
var filterWith = require("allong.es").allong.es.filterWith;!!function isEven(x){return x%2 === 0;};!var evenOnly = filterWith(isEven);!!evenOnly([1, 2, 3]);![ 2 ]!!evenOnly([42, 113]);![ 42 ]!!evenOnly([2, 1232, 131, 2, 13]);![ 2, 1232, 2 ]
var! allonges = require("allong.es").allong.es,! filterWith = allonges.filterWith
var filter = binary( function filter (list, fn) {! fn = functionalize(fn);! ! return __filter.call(list, fn);!});! ! var filterWith = flip(filter);
filterWith
arrayfunction
var filter = binary( function filter (list, fn) {! fn = functionalize(fn);! ! return __filter.call(list, fn);!});! ! var filterWith = flip(filter);
Multimethods
Environment
Method
Predicate FunctionName
Environment
Method
Predicate FunctionName
(name, predicate)
name
predicate func
tion
var! bilby = require("bilby"),! environment = bilby.environment;
animals
voice
isA sayspeak
var environment = require("bilby").environment;!var animals = environment();!!function voice(type, sound){! return ["The", type, "says", sound].join(" ");!};!!function isA(thing){! return function(obj){! return obj.type == thing;! };!};!!function say(sound){! return function(obj){! console.log(voice(obj.type, sound));! };!};
animals
voice
isA sayspeak
var environment = require("bilby").environment;!var animals = environment();!!function voice(type, sound){! return ["The", type, "says", sound].join(" ");!};!!function isA(thing){! return function(obj){! return obj.type == thing;! };!};!!function say(sound){! return function(obj){! console.log(voice(obj.type, sound));! };!};
method
environment
predicate
function
Animals
voice
cat meowspeak
(speak, cat)
speak
cat
meo
w
var animals = animals.method(! “speak",! isA(“cat"),! say("meow"));!var animals = animals.method(! “speak",! isA(“dog"),! say("woof"));!!
animals.speak({type: "dog"});!The dog says woof!!
animals.speak({type: "cat"});!The cat says meow
Animals
voice
cat meowspeak
(speak, cat)
speak
cat
meo
w
var animals = animals.method(! “speak",! isA(“cat"),! say("meow"));!var animals = animals.method(! “speak",! isA(“dog"),! say("woof"));!!
animals.speak({type: "dog"});!The dog says woof!!
animals.speak({type: "cat"});!The cat says meow
namepredicate
function
environment
“What does the fox say?”
var animals = animals.method(! "speak",! isA("fox"),! say(“Wa-pa-pa-pa-pa-pa-pow!")!);!!
animals.speak({type:"fox"});!The fox says Wa-pa-pa-pa-pa-pa-pow!
Dante, The Divine Comedy Canto 24
A longer ladder yet remains to scale.
Functional JavaScriptMichael Fogus
JavaScript AllongeReginald Braithwaite
Learn You a Haskell for Great Good!
Miran Lipovača
The Joy of ClojureMichael Fogus$Chris Houser
Nietzsche, Human, All Too Human Aphorism 633
Now we will no longer concede so easily that anyone has the truth.
Thank you.
Mike Harris@MikeMKH!http://comp-phil.blogspot.com/