On Github ychartois / Presentation-CorkDev.io-2015
What Every Hipster Should Know About Functional Programming
Now that we have lambdas in Java 8, can we use FP concepts?
Is there an advantage to use these concepts in other language with First Class Function as Javascript
Definition
“A programming language is said to have first-class functions if it treats functions as first-class citizens”Code:
Function< String, String > hello = (String s) -> "hello " + s;
Result:
hello ; // BaseConcepts$$Lambda$1@a09ee92 // != BaseConcepts@30f39991 hello.apply("Erouan") ; // hello Erouan
Definition
“It's a function that takes one or more function as parameters or that returns a function”Code:
Function< String, String > twice( Function< String, String > f ) { return (String s) -> f.apply( f.apply(s) ); }
Resultat:
twice(hello).apply("Erouan"); // hello hello Erouan
Code:
hello = (s) -> return "Hello " + s twice = (func, s) -> return func func s
Resultat:
twice(hello,"Erouan") // hello hello Erouan
Definition
“Currying is the technique of translating the evaluation of a function that takes multiple arguments (or a tuple of arguments) into evaluating a sequence of functions, each with a single argument”Previous code:
twice = (func, s) -> return func func s
Currying code:
twice = ( func ) -> ( s ) -> return func func s
Result:
twice(hello)("Erouan") // hello hello Erouan
Definition
“A functor is a collection of X that can apply a function f : X → Y over itself to create a collection of Y.”Code:
List< String > map( Function< String, String > f , List< String > values ) { List< String > toReturn = new ArrayList< >(); for( String current : values ) { toReturn.add( f.apply(current) ); } return toReturn; }
Result:
List< String > confs = Arrays.asList( new String[]{"Corkdev", "devoxx", "javaone"} ); map( s -> s.toUpperCase(), confs ); // [CORKDEV, DEVOXX, JAVAONE]
With Java 8:
confs.stream().map( s -> s.toUpperCase() ).collect( Collectors.toList() )
With Coffescript:
["Corkdev", "devoxx", "javaone"].map (el) -> el.toUpperCase()
Code:
List< String > filter( Function< String, Boolean > f, List< String > values ) { List< String > toReturn = new ArrayList< >(); for( String current : values ) { if ( f.apply(current) ) toReturn.add( current ); } return toReturn; }
Result:
List< String > confs = Arrays.asList( new String[]{"jug", "devoxx", "javaone"} ); filter(s -> s.contains("j"), confs) ; // [jug, javaone]
With Java 8:
confs.stream().filter( s -> s.contains("j") ).collect(Collectors.toList())
With Coffescript:
["Corkdev", "devoxx", "javaone"].filter (el) -> el.indexOf('k') != -1
Definition
“Fold is a family of higher order functions that process a data structure in some order and build a return value”Code:
String reduce( BinaryOperator< String > op , List< String > values ) { String toReturn = ""; for( String current : values ) { toReturn = toReturn.isEmpty() ? current : op.apply(toReturn, current) } return toReturn; }
Result:
List< String > confs = Arrays.asList( "Corkdev", "devoxx", "javaone" ); reduce( (s1, s2) -> s1 + ", " + S2, confs ); // Corkdev, devoxx, javaone
With Java 8:
confs.stream().reduce((s1, s2) -> s1 + ", " + s2 ).get() )
With Coffescript:
["Corkdev", "devoxx", "javaone"].reduce (e1, e2) -> e1 + ", " + e2
Definition
“One definition of a combinator is a function with no free variables.”Constat:
List< String > confs2 = Arrays.asList( new String[] {"jug", "devoxx", "javaone", null} ); map( s -> s.toUpperCase(), confs2); // Exception in thread "main" java.lang.NullPointerException
Code:
Function< String, String > nullCheck( Function< String, String > f ) { return (String s) -> s == null ? "null" : f.apply(s); }
Result:
map( nullCheck(s -> s.toUpperCase()), confs2) // [JUG, DEVOXX, JAVAONE, null]
Definition
“Combine several functions to create a new function”Code:
Function< String, String > compose ( Function< String, String > f1, Function< String, String > f2 ) { return (String s) -> f1.apply( f2.apply(s) ); }
Result:
Function< String, String > up = (String s) -> s.toUpperCase(); Function< String, String > hello = (String s) -> "hello " + s; up.apply( hello.apply("Erouan") ); compose( up, hello).apply("Erouan") ; // HELLO EROUAN
With Java 8:
hello.andThen(up).apply("Erouan") up.compose(hello).apply("Erouan")
Code Coffee:
compose = (fs...) -> fs.reduce (f, g) -> (as...) -> f g as...
Code JS:
compose = function() { var fs; fs = 1 <= arguments.length ? slice.call(arguments, 0) : []; return fs.reduce(function(f, g) { return function() { var as; as = 1 <= arguments.length ? slice.call(arguments, 0) : []; return f(g.apply(null, as)); }; }); };
Result:
up = (s) -> s.toUpperCase() hello = (s) -> "Hello " + s compose(up, hello) "Pierre" // HELLO PIERRE
names = ["Pierre", "John", "Colm", "Petra", "Lenka"] up = (s) -> s.toUpperCase() hello = (s) -> "Hello " + s
Because for me that:
names.filter( (el) -> el.indexOf('k') == -1 ) .map( (el) -> compose(up, hello)(el) ) .reduce( (e1, e2) -> e1 + ", " + e2 )
Is more readable than:
acc = "" for name in names if name.indexOf('k') == -1 if acc != "" acc += ", " + up hello name else acc += up hello name