Share
Embed
Functional Programming Fundamentals in JS & PHP
Slide deck from talk given at Triangle JS / PHP / MySQL meetup.
krisjordan
January 24, 2012
Transcript
65 slides
-
Learn Functional Programming (by implementing a SQL DSL) in JavaScript
and PHP @KrisJordan Tuesday, January 24, 12 -
Who am I? • Kris Jordan • Founder at New
Media Campaigns • Ping me via... • Twitter: @KrisJordan • GitHub: KrisJordan • Email: [email protected] • KrisJodan.com @KrisJordan Tuesday, January 24, 12 -
Main Street, Carrboro N E W M E D I
A C A M P A I G N S Tuesday, January 24, 12 -
Objectives 1. Grok functional programming fundamentals 2. Familiarity with underscore.(js|php)
3. Transfer SQL knowledge to FP @KrisJordan Tuesday, January 24, 12 -
$(“p”).each(function(){ $(this).wrap(“<marquee/>”); }); 1. We already use functional programming techniques
@KrisJordan Tuesday, January 24, 12 -
with fewer bugs and think differently 3. You’ll write less
code about programming. @KrisJordan Tuesday, January 24, 12 -
// JavaScript here <?php // php here Title here. Tuesday,
January 24, 12 -
Functions are data. var logMessage = function(){ console.log(“Hello, world.”); };
logMessage(); $logMessage = function(){ echo(“Hello, world.”); }; $logMessage(); Tuesday, January 24, 12 -
Functions can be passed to Executor functions. var executor =
function(aFunction){ aFunction(); } executor(logMessage); $executor = function($aFunction){ $aFunction(); }; $executor($logMessage); Tuesday, January 24, 12 -
jQuery’s API is awesome thanks to Executor functions. $(‘h1’).click(function(){ console.log(“Hello,
world”); }); @KrisJordan $(“p”).each(function(){ $(this).wrap(“<marquee/>”); }); Tuesday, January 24, 12 -
map( 3 2 1 , function(item){ return item * item;
} ); @KrisJordan Tuesday, January 24, 12 -
map( 3 2 1 , function(item){ return item * item;
} ); @KrisJordan Tuesday, January 24, 12 -
map( 3 2 1 , function(item){ return item * item;
} ); 9 @KrisJordan Tuesday, January 24, 12 -
map( 3 2 1 , function(item){ return item * item;
} ); 9 4 @KrisJordan Tuesday, January 24, 12 -
map( 3 2 1 , function(item){ return item * item;
} ); 9 4 1 @KrisJordan Tuesday, January 24, 12 -
map( 3 2 1 , function(item){ return item * item;
} ); 9 4 1 return to caller @KrisJordan Tuesday, January 24, 12 -
map implemented var map = function(collection, fn) { var rv
= []; for(var i = 0; i < collection.length; i++){ var item = collection[i]; rv.push(fn(item)); } return rv; } $map = function($collection, $fn) { $rv = array(); for($i = 0; $i < count($collection); i++){ $item = $collection[$i]; $rv[] = $fn($item); } return $rv; } Tuesday, January 24, 12 -
filter( 3 2 1 ,function(item){ return item % 2 ===
1; } ); @KrisJordan Tuesday, January 24, 12 -
filter( 3 2 1 ,function(item){ return item % 2 ===
1; } ); true? yes 3 @KrisJordan Tuesday, January 24, 12 -
filter( 3 2 1 ,function(item){ return item % 2 ===
1; } ); true? no! 3 @KrisJordan Tuesday, January 24, 12 -
filter( 3 2 1 ,function(item){ return item % 2 ===
1; } ); true? yes 3 1 @KrisJordan Tuesday, January 24, 12 -
filter( 3 2 1 ,function(item){ return item % 2 ===
1; } ); 3 1 return to caller @KrisJordan Tuesday, January 24, 12 -
pluralFn( item item item , singularFn ); executor how can
we do better here? @KrisJordan Tuesday, January 24, 12 -
Executor Function Anonymous Function Function Variable var toggleSelected = function(){
$(this).toggleClass(“selected”); }; $(‘h1’).click(toggleSelected); @KrisJordan Tuesday, January 24, 12 -
Executor Function Anonymous Function Function Variable Generator Function var toggleClass
= function(klass){ return function(){ $(this).toggleClass(klass); }; }; $(‘h1’).click(toggleClass(“selected”)); Tuesday, January 24, 12 -
Functions can be returned by Generator functions. var genMessageFn =
function(msg) { return function(){console.log(msg);}; }; jQuery(‘h1’).click(genMessageFn(“Hi!”)); $genMessageFn = function($msg) { return function()use($msg){echo($msg);}; }; $executor($genMessageFn(“Hi!”)); Tuesday, January 24, 12 -
Something smells fishy, var genMessageFn = function(msg) { return function(){console.log(msg);};
}; $(‘h1’).click(genMessageFn(“Hi!”)); $genMessageFn = function(msg) { return function()use($msg){echo($msg);}; }; $executor($genMessageFn(“Hi!”)); doesn’t `msg` pop off the stack? Tuesday, January 24, 12 -
Functions can be closures. They “trap” var refs into a
fn’s scope. JS closures are implicit. PHP closures are explicit. function() use($msg) {...} Tuesday, January 24, 12 -
Executor Function Anonymous Function var toggleClass = function(klass){ return function(){
$(this).toggleClass(klass); }; }; $(‘h1’).click(toggleClass(“selected”)); Function Variable Generator Function “Trapped” in Scope by Closure Tuesday, January 24, 12 -
Closures in OOP terms: native, minimal Command pattern class MsgCommand
{ private $_msg; function __construct($msg) { $this->$_msg = $msg; } function exec() { echo $this->_msg; } } $cmd = new MsgCommand(“OOP”); $cmd->exec(); $msgCommand = function($msg) { return function()use($msg) { echo $msg; }; }; $cmd = $msgCommand(“FP”); $cmd(); OOP FP @KrisJordan Tuesday, January 24, 12 -
Refactor to Generator @KrisJordan Anonymous Function Function Variable Generator Function
refactor for reuse refactor for parameters Tuesday, January 24, 12 -
var toggleClassSelected = function(){ $(this).toggleClass(“selected”); }; $(‘h1’).click(toggleClassSelected); $(‘h1’).click(function(){ $(this).toggleClass(“selected”); });
var toggleClass = function(klass){ return function(){ $(this).toggleClass(klass); }; }; $(‘h1’).click(toggleClass(“selected”)); Anon Function Function Variable Generator Function refactor for reuse refactor for parameters refactor for reuse refactor for parameters Tuesday, January 24, 12 -
Let’s Implement a SQL DSL SELECT p.first, p.last, p.games, p.points
FROM players AS p WHERE p.games = 19 ORDER BY p.last @KrisJordan Tuesday, January 24, 12 -
Let’s Implement a SQL DSL SELECT p.first, p.last, p.games, p.points
FROM players AS p WHERE p.games = 19 ORDER BY p.last _.filter _.sortBy _.map _.map @KrisJordan Tuesday, January 24, 12 -
Recap • Functions are data • Closures “trap” variable references
in scope, useful for generating functions • Write singular function generators, leverage with plural executor functions • Underscore provides great executor functions for processing data @KrisJordan Tuesday, January 24, 12 -
any( 3 2 1 ,function(item){ return item % 2 ===
1; } ); Tuesday, January 24, 12 -
any( 3 2 1 ,function(item){ return item % 2 ===
1; } ); true? yes true Tuesday, January 24, 12 -
any( 3 2 1 ,function(item){ return item % 2 ===
1; } ); true? yes true return to caller Tuesday, January 24, 12 -
reject( 3 2 1 ,function(item){ return item % 2 ===
1; } ); Tuesday, January 24, 12 -
reject( 3 2 1 ,function(item){ return item % 2 ===
1; } ); 2 return to caller Tuesday, January 24, 12 -
reduce( 3 2 1 , function(memo,item){ return memo + item;
} ); , 0 Tuesday, January 24, 12 -
reduce( 3 2 1 , function(memo,item){ return memo + item;
} ); 0 , 0 memo Tuesday, January 24, 12 -
reduce( 3 2 1 , ); 0 , 0 memo
function(memo,item){ return 0+3; } Tuesday, January 24, 12 -
reduce( 3 2 1 , ); 3 , 0 memo
function(memo,item){ return 0+3; } Tuesday, January 24, 12 -
reduce( 3 2 1 , ); 3 , 0 memo
function(memo,item){ return 3+2; } Tuesday, January 24, 12 -
reduce( 3 2 1 , ); 5 , 0 memo
function(memo,item){ return 3+2; } Tuesday, January 24, 12 -
reduce( 3 2 1 , ); 5 , 0 memo
function(memo,item){ return 5+1; } Tuesday, January 24, 12 -
reduce( 3 2 1 , ); 6 , 0 memo
function(memo,item){ return 5+1; } Tuesday, January 24, 12 -
reduce( 3 2 1 , function(memo,item){ return memo + item;
} ); 6 , 0 memo return to caller Tuesday, January 24, 12