var λ;Introduction to Functional Programming
with JavaScript(and a little Haskell)
Will Kurt
Will Kurt, Creative Commons Attribution-ShareAlike 3.0
"A language that doesn't effect how you think about
programming is not worth learning"
--Alan Perlis
So what is Functional Programming?
http://www.flickr.com/photos/foundphotoslj/466713478/
What does this mean?
http://www.flickr.com/photos/61417318@N00/4908148942/
No Side Effects!
http://www.flickr.com/photos/rka/1733453/
http://www.flickr.com/photos/23912576@N05/3056871500/
Haskell!
http://www.flickr.com/photos/micurs/4870514382/
JavaScript!!!
http://www.flickr.com/photos/jurvetson/96972777/
Rules for Today
λ
Lists!!!
first( [1,2,3,4]) -> 1 (aka: car, head)
rest( [1,2,3,4] ) -> [2,3,4] (aka: cdr, tail)
empty( [1,2,3,4] ) -> false (aka: null?, nil? empty?,[])
empty( [ ] ) -> true
build( 1 , [2,3,4]) -> [1,2,3,4] (aka: cons, ':' )
build( [1] , [2,3,4]) -> [[1],2,3,4]
Recursion!
"If you already know what recursion is, just remember the answer. Otherwise, find someone who is standing closer to Douglas Hofstadter than you are; then ask him or her what recursion is."
-- Andrew Plotkin
Exercise set 1a
10 minutes
Answers to set 1a
problem 1
var fact = function(x) { return( (x===1) ? 1 : x*fact(x-1) );}
function fact (x) { if(x==1){ return 1; } else { return x*fact2(x-1); }}
problem 2
var fib = function(x){ return( (x==0) ? 0 : (x==1) ? 1 : fib(x-1)+fib(x-2) );
}
problem 2 continued...
var fib_answers = []fib_answers[0] = 0;fib_answers[1] = 1;var fibm = function (x) { return fib_mem(x,fib_answer);}
var fib_mem = function(x,m){ if(m[x] != undefined){ return m[x]; } else { m[x] = fib_mem(x-1,m)+fib_mem(x-2,m); return m[x]; }}
problem 2 last one I swear (also very functional)...
var fib3wrapper = function(c){ return fib3(c,1,0);}
var fib3 = function(c,last1,last2){ return( (c==2) ? last1+last2: fib3(c-1,last1+last2,last1) );}
Exercise set 1b
10 minutes
Answers to set 1b
problem 1
var length = function (xs) { return( empty(xs) ? 0 : 1 + length(rest(xs)) );};
problem 2
var nth = function(n,xs){ return( empty(xs) ? [] : (n == 0) ? first(xs) : nth(n-1, rest(xs)) );
};
problem 3
var removeAll = function (x, xs) { return( empty(xs) ? [ ] : (x == first(xs)) ? removeAll(x, rest(xs)) : build(first(xs), removeAll(x,rest(xs)))
);};
First class functions
http://www.flickr.com/photos/richardmoross/2211308689/
First Class Functions (Haskell)add2 x = 2 + xadd3 x = 3 + x
> add2 57
> add3 58
First Class Functions (Haskell)argIs2 func = (func) 2argIs3 func = (func) 3
> argIs2(add2)4> argIs2(add3)5> argIs3(add2)5> argIs3(add3)6
Lambda Functions
http://www.flickr.com/photos/jeremymates/2362399109/
Lambda Function (Haskell)
add4 = (\x -> 4+x)
>argIs2((\x -> 4+x))6
Lambda Function (JavaScript)
$.ajax({ url: "test.html", context: document.body, success: function(){ $(this).addClass("done"); }});
$("#exec").click(function(){ $("#results").prepend("<li>Normal Handler</li>");});
Exercise set 2
10 minutes
Answers to set 2
problem 1
var argIs2 = function(func) { return func(2);}
problem 2
argIs2(function(x){ add(2,x);} );
problem 3
var flip = function (func) { return( function(x,y){ func(y,x); } );};
Break!
5 minutes
Closures
http://www.flickr.com/photos/theredproject/3431459572/
Closures (Haskell)
add5 = (+5)makeAdder val = (+val)makeAdderWithLambda val = (\x->x+val)
add6 = makeAdder 6add7 = makeAdderWithLambda 7
> add5 510> add6 511> add7 512
Exercise set 3
5 minutes
Answers to set 3
problem 1
var makeAdder = function (x) { return( function(y) { return add(x,y); } );};
problem 2
var apiClosure = function(apiKey){ return( function(x){ return apiSearch(apiKey,x); } );};
problem 3
var compose = function (f1,f2) { return( function(x){ f1(f2(x)); } );};
Higher Order Functions
http://www.flickr.com/photos/73416633@N00/2425022159/
Map
http://www.flickr.com/photos/rosenkranz/3052214847/
Map (Haskell)
doubleAll xs = map (*2) xssquareAll xs = map (^2) xssquareAndAdd xs = map (\x->x*x+x) xsupperCase s = map toUpper s
> doubleAll [1,2,3,4][2,4,6,8]> squareAll [1,2,3,4][1,4,9,16]> squareAndAdd [1,2,3,4][2,6,12,20]> upperCase "doggie""DOGGIE"
Map (Haskell)
doubleAllv2 = map (*2)squareAllv2 = map (^2)squareAndAddv2 = map (\x->x*x+x)
Exercise set 4a
5 minutes
Answers to set 4a
problem 1
var map = function (func, xs) { return( empty(xs) ? [ ] : build( func(first(xs)), map (func, rest (xs)))); );};
problem 2
map(function(x){ return x*x}, xs);
Filter
Filter (Haskell)
evenList xs = filter even xsmod17list xs = filter (== (`mod` 17) 0) xsdoubleEvens xs = (doubleAll . evenList) xs
> evenList [1,2,3,4,5,6][2,4,6]> mod17list [1..100][17,34,51,68,85]> doubleEvens [0,3..27][0,12,24,36,48]
Exercise set 4b
10 minutes
Answers to set 4b
problem 1
var filter = function (test,xs){ return( empty(xs) ? [ ] : test(first(xs)) ? filter(test, rest(xs)) : build(first(xs),filter(test,rest(xs))) );};
problem 2
var removeAll = function(x,xs){ return( filter(function(y){ return y == x}, xs) );
};
Foldl (Reduce)
http://en.wikipedia.org/wiki/File:Sermon_in_the_Deer_Park_depicted_at_Wat_Chedi_Liem-KayEss-1.jpeg
Foldl (Haskell)
mySum xs = foldl (+) 0 xssumOfSquares xs = foldl (+) 0 (map (^2) xs)sumOfSquaresv2 = (mySum . squareAll)
> mySum [1..2000000]2000001000000> sumOfSquares [1..10]385> sumOfSquaresv2 [1..10]385
Foldl (Haskell)
myReverse xs = foldl (\x y -> y:x) [] xsmyReverse [1,2,3]
foldl (\x y -> y:x) [] [1,2,3]
.. (\[] 1 -> 1:[]) .. => [1]
foldl (\x y -> y:x) [1] [2,3]
.. (\[1] 2 -> 2:[1]) .. => [2,1]
Exercise set 4c
5 minutes
Answers to set 4c
problem 1
var foldl = function (step, init, xs) { return( empty(xs) ? init : foldl(step, step(init,first(xs)), rest(xs)
);};
problem 2
var sum = function(xs) { return foldl(add,0,xs);};
Map (JavaScript) 'The Spolsky Map'
function spolsky_map(fn, a) { for (i = 0; i < a.length; i++) { a[i] = fn(a[i]); } }
note the side effects
The Spolsky Reduce (foldl)
function spolsky_reduce(fn, a, init) { var s = init; for (i = 0; i < a.length; i++) s = fn( s, a[i] ); return s; }
Break
5 minutes
Exercise 5a
5 minutes
Answers to set 5a
problem 1
var last = compose(first,reverse);
problem 2
var reverse = function (xs) { return foldl(flip(build),[ ],xs);};
Standard Deviation
1. calculate the arithmetic mean of the list2. subtract the mean from all the numbers in the list3. square the number in that list4. calculate the sum of the list5. divide the sum by length of list by 16. get the square root of this number
Standard Deviation
1. calculate the arithmetic mean of the list
mean xs = sum xs / fromIntegral(length xs)2. subtract the mean from all the numbers in the list
deviations xs = map (\x -> x - m ) xs where m = mean xs3. square the numbers in that list
squareDeviations xs = map(^2) devs where devs = deviations xs4. calculate the sum of the list
sumSquareDeviations xs = (sum .squareDeviations) xs5. divide the sum by length of list minus 16. get the square root of this number
sd xs = sqrt $ sumSqDev / lsub1 where sumSqDev = sumSquareDeviations xs lsub1 = fromIntegral $ ((-1+) . length)xs
Exercise 5b
10 minutes
Answers to set 5b
Standard Deviation (JavaScript)
var mean = function (xs){ return(sum(xs)/flength(xs));};
var deviations = function (xs) { var m = mean(xs);//we can remove this return map(function(x){return x-m;},xs);};
var squareDeviations = function(xs){ return map(square,deviations(xs));};
Standard Deviation (JavaScript)
var sumSqDeviations = compose(sum,squareDeviations);
var sd = function(xs){ return Math.sqrt( (sumSqDeviations(xs)/(length(xs)-1)));};
Standard Deviation
Haskell> sd [1,4,5,9,2,10]3.65604522218567
JavaScript> sd([1,4,5,9,2,10]);3.65604522218567
Function Currying
Currying (Haskell)
myAdd x y = x + yadd8 = myAdd 8add9 = (+9)
> myAdd 8 917> add8 917> add9 817
Currying (JavaScript)
var curry = function (f,a) { return(function(){ var args = Array.prototype.slice.call(arguments); args.unshift(a); return f.apply(this, args);} );};
Currying (JavaScript) purely functional
var curry = function (f,a) { return(function(){ return((function(args){ return f.apply(this, build(a,args));})(Array.prototype.slice.call(arguments)) );} );};
Currying (JavaScript)
var add_three = function(a,b,c){ return a+b+c;};
>f1 = curry(add_three,1);>f1(2,3)6
>f2 = curry(curry(add_three,1),2);>f2(3)6
Exercise 6
10 minutes
Answers to set 6
problem 1
var makeAdder = curry(add,x);
var apiClosure = curry(apiSearch,apiKey);
problem 2
var unrealisticFunction = function (a, b){ (function(c){ return((function(d){ if(c<d){ return c+d; }else{ return c*d; } };)(c+a) ); })(a*b)};
Still have time?
awesome!
Haskell vs JavaScript
Types!!!
areaOfTrapezoid :: Float -> Float -> Float -> FloatareaOfTrapezoid h b1 b2 = 0.5*h*(b1+b2)
evenList :: (Integral a) => [a] -> [a]evenList xs = filter even xs
Lazy Evaluation!!!
[2,4..] !! 108> 218
Pattern MatchingpatternMatch [a,b,c] = b ++ c ++ apatternMatch [a,b] = a ++ bpatternMatch [] = "no list"patternMatch as = "a larger list"
Pattern MatchingpatternMatch ["a","b","c"]>"bca"patternMatch ["a","b"]>"ab"patternMatch [ ]>"no list"patternMatch ["a","b","c","d"]>"a larger list"
Who actually uses this stuff?
http://cufp.org/
Ocaml
more @ http://www.scala-lang.org/node/1658
Haskell
... continued
more @ http://haskell.org/haskellwiki/Haskell_in_industry