Slide 1

Slide 1 text

© 2014 Guillaume Laforge. All rights reserved. Do not distribute without permission. Guillaume Laforge 
 @glaforge Functional Groovy

Slide 2

Slide 2 text

Guillaume Laforge Groovy project lead ! @glaforge http://www.google.com/+GuillaumeLaforge http://glaforge.appspot.com

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Pivotal related talks • Thursday – 2:15pm - 3:15pm •Advanced Web Development Techniques with Grails 2 — Jeff Brown •Making the Eclipse IDE fun again — Martin Lippert ! • Friday – 9:00am - 5:00pm •From the database into the web: End-to-end REST web services with Spring — Oliver Gierke 4

Slide 5

Slide 5 text

Part 1
 a Groovy primer

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

Simplify the life of (Java) developers

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

Groovy as a Java superset

Slide 10

Slide 10 text

It’s so easy to learn! Groovy as a Java superset

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

Great for scripting

Slide 14

Slide 14 text

Great for scripting Fit for Domain- Specific Languages

Slide 15

Slide 15 text

Great for scripting Fit for Domain- Specific Languages Most seamless integration & interoperability wih java!

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

class  MathSpec  extends  Specification  {          def  "maximum  of  two  numbers"()  {              expect:                  Math.max(a,  b)  ==  c   !            where:                  a  |  b  ||  c                  1  |  3  ||  3                  7  |  4  ||  4                  0  |  0  ||  0          }   }

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

new  MarkupBuilder().html  {          head  {                  title  "The  Script  Bowl"          }   !        body  {                  div(class:  "banner")  {                          p  "Groovy  rocks!"                  }          }   }

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

move  forward  at  3.km/h Expressive, Concise, Readable

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

@RestController   class  App  {          @RequestMapping("/")          String  home()  {  "Hello  World!"  }   } Speaking of conciseness... A full Spring app in the span of a tweet!

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

AssafeandfastasJava with statictypechecking & compilation

Slide 27

Slide 27 text

AssafeandfastasJava with statictypechecking & compilation

Slide 28

Slide 28 text

million 
 downloads
 in 2013 3.0

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

Yup, we’re all using Groovy!

Slide 32

Slide 32 text

Part 2
 Community

Slide 33

Slide 33 text

A blossoming Ecosystem

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

GVM

Slide 39

Slide 39 text

Part 3 Functional

Slide 40

Slide 40 text

What is a functional language?

Slide 41

Slide 41 text

What is a functional language? Functions, closures, lambdas Immutability Side-effect free / pure Persistent collections Recursion Higher Order Functions Partial application Concurrency, parallelism Monads, functors, combinators... Composition Map / filter / reduce Lazy vs Eager Memoization Infinite streams

Slide 42

Slide 42 text

No content

Slide 43

Slide 43 text

Closures as first-class citizens of the language

Slide 44

Slide 44 text

Closures everywhere in Groovy APIs • Closures are used in many situations: – iterators – callbacks – higher-order functions – custom control structures – dynamic method definition – resource allocation and handling – threads creation and launch – continuation-like coding – ... 26

Slide 45

Slide 45 text

Closures — the basics 27 def  adder  =  {  a,  b  -­‐>  a  +  b  }   ! assert  adder(1,  2)  ==  3   assert  adder('a',  'b')  ==  'ab'

Slide 46

Slide 46 text

Closures — the basics 27 def  adder  =  {  a,  b  -­‐>  a  +  b  }   ! assert  adder(1,  2)  ==  3   assert  adder('a',  'b')  ==  'ab' Closure parameters

Slide 47

Slide 47 text

Closures — the basics 27 def  adder  =  {  a,  b  -­‐>  a  +  b  }   ! assert  adder(1,  2)  ==  3   assert  adder('a',  'b')  ==  'ab' Assign a function into a variable Closure parameters

Slide 48

Slide 48 text

Closures — the basics 27 def  adder  =  {  a,  b  -­‐>  a  +  b  }   ! assert  adder(1,  2)  ==  3   assert  adder('a',  'b')  ==  'ab' Short form of: adder.call(‘a’, ‘b’) Assign a function into a variable Closure parameters

Slide 49

Slide 49 text

Closures — the basics 27 def  adder  =  {  a,  b  -­‐>  a  +  b  }   ! assert  adder(1,  2)  ==  3   assert  adder('a',  'b')  ==  'ab' Short form of: adder.call(‘a’, ‘b’) Genericity with duck typing & operator overloading Assign a function into a variable Closure parameters

Slide 50

Slide 50 text

Closures — explicit types 28 ! def  intAdder  =  {  int  a,  int  b  -­‐>  a  +  b  }  

Slide 51

Slide 51 text

Closures — explicit types 28 ! def  intAdder  =  {  int  a,  int  b  -­‐>  a  +  b  }   Be explicit about the types

Slide 52

Slide 52 text

Closures — implicit parameter 29 def  doubler  =  {  it  *  2  }   ! assert  doubler(3)  ==  6   assert  doubler('a')  ==  'aa'

Slide 53

Slide 53 text

Closures — implicit parameter 29 def  doubler  =  {  it  *  2  }   ! assert  doubler(3)  ==  6   assert  doubler('a')  ==  'aa' Implicit parameter

Slide 54

Slide 54 text

Closures — implicit parameter 29 def  doubler  =  {  it  *  2  }   ! assert  doubler(3)  ==  6   assert  doubler('a')  ==  'aa' Implicit parameter Multiply also defined on strings

Slide 55

Slide 55 text

Closures — variable arguments 30 def  sum  =  {  ...  elements  -­‐>  
                                elements.sum()  }   ! assert  sum(1,  2)  ==  3   assert  sum('a',  'b',  'c')  ==  'abc'

Slide 56

Slide 56 text

Closures — variable arguments 30 def  sum  =  {  ...  elements  -­‐>  
                                elements.sum()  }   ! assert  sum(1,  2)  ==  3   assert  sum('a',  'b',  'c')  ==  'abc' Variable number of arguments

Slide 57

Slide 57 text

Closures — variable arguments 30 def  sum  =  {  ...  elements  -­‐>  
                                elements.sum()  }   ! assert  sum(1,  2)  ==  3   assert  sum('a',  'b',  'c')  ==  'abc' You can specify the type: int... Variable number of arguments

Slide 58

Slide 58 text

Closures — default values 31 def  mult  =  {  int  a,  int  b  =  10  -­‐>  a  *  b  }   ! assert  mult(2,  3)  ==  6   assert  mult(5)  ==  50

Slide 59

Slide 59 text

Closures — default values 31 def  mult  =  {  int  a,  int  b  =  10  -­‐>  a  *  b  }   ! assert  mult(2,  3)  ==  6   assert  mult(5)  ==  50 Default value

Slide 60

Slide 60 text

Closures — default values 31 def  mult  =  {  int  a,  int  b  =  10  -­‐>  a  *  b  }   ! assert  mult(2,  3)  ==  6   assert  mult(5)  ==  50 Default value Provided value for b

Slide 61

Slide 61 text

Closures — default values 31 def  mult  =  {  int  a,  int  b  =  10  -­‐>  a  *  b  }   ! assert  mult(2,  3)  ==  6   assert  mult(5)  ==  50 Default value Provided value for b Default value used for b

Slide 62

Slide 62 text

Closures — methods as functions 32 def  logBase10  =  Math.&log10   def  printer  =  System.out.&println   ! assert  logBase10(10)  ==  1   printer  'abc'

Slide 63

Slide 63 text

Closures — methods as functions 32 def  logBase10  =  Math.&log10   def  printer  =  System.out.&println   ! assert  logBase10(10)  ==  1   printer  'abc' Turn a method into a closure function

Slide 64

Slide 64 text

Closures — iterations 33 def  fruits  =  ['apple',  
                            'orange',  
                            'banana']   ! fruits.each  {  println  it  }   fruits.each  printer

Slide 65

Slide 65 text

Closures — iterations 33 def  fruits  =  ['apple',  
                            'orange',  
                            'banana']   ! fruits.each  {  println  it  }   fruits.each  printer Internal iteration

Slide 66

Slide 66 text

Closures — iterations 33 def  fruits  =  ['apple',  
                            'orange',  
                            'banana']   ! fruits.each  {  println  it  }   fruits.each  printer Internal iteration Pass a method closure

Slide 67

Slide 67 text

Closures — infinite streams 34 def  ints  =  1..1000   ! def  r  =  ints.dropWhile  {  it  <  10  }                          .take(  3  )   ! assert  r  ==  [10,  11,  12]

Slide 68

Slide 68 text

Closures — infinite streams 34 def  ints  =  1..1000   ! def  r  =  ints.dropWhile  {  it  <  10  }                          .take(  3  )   ! assert  r  ==  [10,  11,  12] Could use an infinite iterator

Slide 69

Slide 69 text

Closures — infinite streams 34 def  ints  =  1..1000   ! def  r  =  ints.dropWhile  {  it  <  10  }                          .take(  3  )   ! assert  r  ==  [10,  11,  12] Could use an infinite iterator take(), takeWhile(), drop(), dropWhile()

Slide 70

Slide 70 text

Closures — infinite streams 34 def  ints  =  1..1000   ! def  r  =  ints.dropWhile  {  it  <  10  }                          .take(  3  )   ! assert  r  ==  [10,  11,  12] Could use an infinite iterator take(), takeWhile(), drop(), dropWhile() Returns an iterator

Slide 71

Slide 71 text

Closures — infinite streams 34 def  ints  =  1..1000   ! def  r  =  ints.dropWhile  {  it  <  10  }                          .take(  3  )   ! assert  r  ==  [10,  11,  12] Could use an infinite iterator take(), takeWhile(), drop(), dropWhile() Returns an iterator Variants for maps too

Slide 72

Slide 72 text

Closures — map / filter / reduce 35 3 } map filter reduce

Slide 73

Slide 73 text

Closures — map / filter / reduce 36

Slide 74

Slide 74 text

Closures — map / filter / reduce 36 @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 }

Slide 75

Slide 75 text

Closures — map / filter / reduce 36 @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 }

Slide 76

Slide 76 text

Closures — map / filter / reduce 36 @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } def  persons  =  [
        new  Person('Guillaume',  36),
        new  Person('Marion',  6),
        new  Person('Erine',  1)
 ]

Slide 77

Slide 77 text

Closures — map / filter / reduce 36 @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } def  persons  =  [
        new  Person('Guillaume',  36),
        new  Person('Marion',  6),
        new  Person('Erine',  1)
 ]

Slide 78

Slide 78 text

Closures — map / filter / reduce 36 @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } def  persons  =  [
        new  Person('Guillaume',  36),
        new  Person('Marion',  6),
        new  Person('Erine',  1)
 ] def  names  =
        persons.findAll  {  it.age  <  18  }
                      .collect  {  it.name.toUpperCase()  }
                      .sort()
                      .join(',  ')

Slide 79

Slide 79 text

Closures — map / filter / reduce 36 @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } def  persons  =  [
        new  Person('Guillaume',  36),
        new  Person('Marion',  6),
        new  Person('Erine',  1)
 ] def  names  =
        persons.findAll  {  it.age  <  18  }
                      .collect  {  it.name.toUpperCase()  }
                      .sort()
                      .join(',  ')

Slide 80

Slide 80 text

Closures — map / filter / reduce 36 @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } def  persons  =  [
        new  Person('Guillaume',  36),
        new  Person('Marion',  6),
        new  Person('Erine',  1)
 ] def  names  =
        persons.findAll  {  it.age  <  18  }
                      .collect  {  it.name.toUpperCase()  }
                      .sort()
                      .join(',  ') assert  names  ==  "ERINE,  MARION"

Slide 81

Slide 81 text

Closures — map / filter / reduce 36 @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } def  persons  =  [
        new  Person('Guillaume',  36),
        new  Person('Marion',  6),
        new  Person('Erine',  1)
 ] def  names  =
        persons.findAll  {  it.age  <  18  }
                      .collect  {  it.name.toUpperCase()  }
                      .sort()
                      .join(',  ') assert  names  ==  "ERINE,  MARION" find/findAll, inject, collect, flatten, min/max, unique, reverse, collate, groupBy, any/ every, head/tail/last, count/ countBy, combinations/ permutations/subsequences/ transpose, withDefault/ withLazyDefault

Slide 82

Slide 82 text

Closures — Closures vs Java 8 lambdas? 37

Slide 83

Slide 83 text

Closures — Closures vs Java 8 lambdas? 37 IntStream.range(1,  100).forEach(s  -­‐>  System.out.println(s));   ! Files.lines(Paths.get('README.adoc'))            .map(it  -­‐>  it.toUpperCase())            .forEach(it  -­‐>  System.out.println  it);

Slide 84

Slide 84 text

Closures — Closures vs Java 8 lambdas? 37 IntStream.range(1,  100).forEach  {  println  it  }   ! Files.lines(Paths.get('README.adoc'))            .map  {  it.toUpperCase()  }            .forEach  {  println  it  } IntStream.range(1,  100).forEach(s  -­‐>  System.out.println(s));   ! Files.lines(Paths.get('README.adoc'))            .map(it  -­‐>  it.toUpperCase())            .forEach(it  -­‐>  System.out.println  it);

Slide 85

Slide 85 text

Closures — Closures vs Java 8 lambdas? 37 IntStream.range(1,  100).forEach  {  println  it  }   ! Files.lines(Paths.get('README.adoc'))            .map  {  it.toUpperCase()  }            .forEach  {  println  it  } IntStream.range(1,  100).forEach(s  -­‐>  System.out.println(s));   ! Files.lines(Paths.get('README.adoc'))            .map(it  -­‐>  it.toUpperCase())            .forEach(it  -­‐>  System.out.println  it); Use Groovy closures wherever you pass lambdas in Java 8

Slide 86

Slide 86 text

Closures — map / filter / reduce & GPars 38

Slide 87

Slide 87 text

Closures — map / filter / reduce & GPars 38 import  static  groovyx.gpars.GParsPool.withPool
 
 withPool  {

Slide 88

Slide 88 text

Closures — map / filter / reduce & GPars 38 import  static  groovyx.gpars.GParsPool.withPool
 
 withPool  {        def  oneStarters  =  (1..30).parallel
                        .map        {  it  **  2  }
                        .filter  {  it  ==~  /1.*/  }

Slide 89

Slide 89 text

Closures — map / filter / reduce & GPars 38 import  static  groovyx.gpars.GParsPool.withPool
 
 withPool  {        def  oneStarters  =  (1..30).parallel
                        .map        {  it  **  2  }
                        .filter  {  it  ==~  /1.*/  }

Slide 90

Slide 90 text

Closures — map / filter / reduce & GPars 38 import  static  groovyx.gpars.GParsPool.withPool
 
 withPool  {        def  oneStarters  =  (1..30).parallel
                        .map        {  it  **  2  }
                        .filter  {  it  ==~  /1.*/  }        assert  oneStarters.collection  ==
                [1,  16,  100,  121,  144,  169,  196]

Slide 91

Slide 91 text

Closures — map / filter / reduce & GPars 38 import  static  groovyx.gpars.GParsPool.withPool
 
 withPool  {        def  oneStarters  =  (1..30).parallel
                        .map        {  it  **  2  }
                        .filter  {  it  ==~  /1.*/  }        assert  oneStarters.collection  ==
                [1,  16,  100,  121,  144,  169,  196]

Slide 92

Slide 92 text

Closures — map / filter / reduce & GPars 38 import  static  groovyx.gpars.GParsPool.withPool
 
 withPool  {        def  oneStarters  =  (1..30).parallel
                        .map        {  it  **  2  }
                        .filter  {  it  ==~  /1.*/  }        assert  oneStarters.collection  ==
                [1,  16,  100,  121,  144,  169,  196]        assert  oneStarters.max()  ==  196
        assert  oneStarters.reduce  {  a,  b  -­‐>  a+b  }  ==  747
        assert  oneStarters.sum()  ==  747
 }

Slide 93

Slide 93 text

Closures — map / filter / reduce & GPars 38 import  static  groovyx.gpars.GParsPool.withPool
 
 withPool  {        def  oneStarters  =  (1..30).parallel
                        .map        {  it  **  2  }
                        .filter  {  it  ==~  /1.*/  }        assert  oneStarters.collection  ==
                [1,  16,  100,  121,  144,  169,  196]        assert  oneStarters.max()  ==  196
        assert  oneStarters.reduce  {  a,  b  -­‐>  a+b  }  ==  747
        assert  oneStarters.sum()  ==  747
 } in parallel!

Slide 94

Slide 94 text

Closures — map / filter / reduce & GPars 38 import  static  groovyx.gpars.GParsPool.withPool
 
 withPool  {        def  oneStarters  =  (1..30).parallel
                        .map        {  it  **  2  }
                        .filter  {  it  ==~  /1.*/  }        assert  oneStarters.collection  ==
                [1,  16,  100,  121,  144,  169,  196]        assert  oneStarters.max()  ==  196
        assert  oneStarters.reduce  {  a,  b  -­‐>  a+b  }  ==  747
        assert  oneStarters.sum()  ==  747
 } in parallel! result still «parallel»

Slide 95

Slide 95 text

GPars • Groovy library bundled with the distribution ! • Provides: – actors – safe agents – dataflow concurrency – data parallelism •fork / join, map / filter / reduce – asynchronous functions – parallel arrays – java.util.concurrent sugar 39

Slide 96

Slide 96 text

GPars • Groovy library bundled with the distribution ! • Provides: – actors – safe agents – dataflow concurrency – data parallelism •fork / join, map / filter / reduce – asynchronous functions – parallel arrays – java.util.concurrent sugar 39 Concurrency & parallelism toolkit for Groovy

Slide 97

Slide 97 text

Closures — resource handling 40 new  File('bible.txt').withReader  {  r  -­‐>          new  File('out.txt').withWriter  {  w  -­‐>                  r.eachLine  {  line  -­‐>                          if  (line.contains('Groovy'))                                  w  <<  line.toUpperCase()                  }          }   }

Slide 98

Slide 98 text

Closures — resource handling 40 new  File('bible.txt').withReader  {  r  -­‐>          new  File('out.txt').withWriter  {  w  -­‐>                  r.eachLine  {  line  -­‐>                          if  (line.contains('Groovy'))                                  w  <<  line.toUpperCase()                  }          }   } Take care of properly opening / closing resources

Slide 99

Slide 99 text

Closures — custom control structures 41 void  unless(boolean  cond,  Closure  c)  {          if  (!cond)  c()   }   ! unless  (10  <  9)  {          println  "less"   }

Slide 100

Slide 100 text

Closures — custom control structures 41 void  unless(boolean  cond,  Closure  c)  {          if  (!cond)  c()   }   ! unless  (10  <  9)  {          println  "less"   } Closure as last argument

Slide 101

Slide 101 text

Closures — custom control structures 41 void  unless(boolean  cond,  Closure  c)  {          if  (!cond)  c()   }   ! unless  (10  <  9)  {          println  "less"   } Closure as last argument Equivalent to: unless(10<9, {...})

Slide 102

Slide 102 text

Closures — builders 42 new  MarkupBuilder().html  {          head  {                  title  "The  Script  Bowl"          }   !        body  {                  div(class:  "banner")  {                          p  "Groovy  rocks!"                  }          }   }

Slide 103

Slide 103 text

Closures — builders 42 new  MarkupBuilder().html  {          head  {                  title  "The  Script  Bowl"          }   !        body  {                  div(class:  "banner")  {                          p  "Groovy  rocks!"                  }          }   } Closure

Slide 104

Slide 104 text

Closures — higher order functions 43

Slide 105

Slide 105 text

Closures — higher order functions 43 sell  100.shares  of  GOOG  at  1000.dollars

Slide 106

Slide 106 text

Closures — higher order functions 43

Slide 107

Slide 107 text

Closures — higher order functions 43 Number.metaClass.getShares  =  {  delegate  }
 Number.metaClass.getDollars  =  {  delegate  }


Slide 108

Slide 108 text

Closures — higher order functions 43 Number.metaClass.getShares  =  {  delegate  }
 Number.metaClass.getDollars  =  {  delegate  }
 String  GOOG  =  "Google"

Slide 109

Slide 109 text

Closures — higher order functions 43 Number.metaClass.getShares  =  {  delegate  }
 Number.metaClass.getDollars  =  {  delegate  }
 String  GOOG  =  "Google"

Slide 110

Slide 110 text

Closures — higher order functions 43 Number.metaClass.getShares  =  {  delegate  }
 Number.metaClass.getDollars  =  {  delegate  }
 String  GOOG  =  "Google" def  sell(int  nShares)  {
        [of:  {  String  ticker  -­‐>
                [at:  {  int  price  -­‐>
                        println  "Sold  ${nShares}  ${ticker}  at  \$${price}"
                }]
        }]
 }

Slide 111

Slide 111 text

Closures — higher order functions 43 Number.metaClass.getShares  =  {  delegate  }
 Number.metaClass.getDollars  =  {  delegate  }
 String  GOOG  =  "Google" def  sell(int  nShares)  {
        [of:  {  String  ticker  -­‐>
                [at:  {  int  price  -­‐>
                        println  "Sold  ${nShares}  ${ticker}  at  \$${price}"
                }]
        }]
 }

Slide 112

Slide 112 text

Closures — higher order functions 43 Number.metaClass.getShares  =  {  delegate  }
 Number.metaClass.getDollars  =  {  delegate  }
 String  GOOG  =  "Google" def  sell(int  nShares)  {
        [of:  {  String  ticker  -­‐>
                [at:  {  int  price  -­‐>
                        println  "Sold  ${nShares}  ${ticker}  at  \$${price}"
                }]
        }]
 } sell  100.shares  of  GOOG  at  1000.dollars

Slide 113

Slide 113 text

Closures — higher order functions 43 Number.metaClass.getShares  =  {  delegate  }
 Number.metaClass.getDollars  =  {  delegate  }
 String  GOOG  =  "Google" def  sell(int  nShares)  {
        [of:  {  String  ticker  -­‐>
                [at:  {  int  price  -­‐>
                        println  "Sold  ${nShares}  ${ticker}  at  \$${price}"
                }]
        }]
 } sell  100.shares  of  GOOG  at  1000.dollars Add properties to numbers

Slide 114

Slide 114 text

Closures — higher order functions 43 Number.metaClass.getShares  =  {  delegate  }
 Number.metaClass.getDollars  =  {  delegate  }
 String  GOOG  =  "Google" def  sell(int  nShares)  {
        [of:  {  String  ticker  -­‐>
                [at:  {  int  price  -­‐>
                        println  "Sold  ${nShares}  ${ticker}  at  \$${price}"
                }]
        }]
 } sell  100.shares  of  GOOG  at  1000.dollars Add properties to numbers Nested maps and closures

Slide 115

Slide 115 text

Closures — higher order functions 43 Number.metaClass.getShares  =  {  delegate  }
 Number.metaClass.getDollars  =  {  delegate  }
 String  GOOG  =  "Google" def  sell(int  nShares)  {
        [of:  {  String  ticker  -­‐>
                [at:  {  int  price  -­‐>
                        println  "Sold  ${nShares}  ${ticker}  at  \$${price}"
                }]
        }]
 } sell  100.shares  of  GOOG  at  1000.dollars Add properties to numbers Nested maps and closures Readable & expressive DSL

Slide 116

Slide 116 text

No content

Slide 117

Slide 117 text

Now what about some curry?

Slide 118

Slide 118 text

Closures — partial application 45 def  mult  =  {  int  a,  int  b  -­‐>  a  *  b  }   def  multByTwo  =  mult.curry(2)   ! assert  multByTwo(3)  ==  6

Slide 119

Slide 119 text

Closures — partial application 45 def  mult  =  {  int  a,  int  b  -­‐>  a  *  b  }   def  multByTwo  =  mult.curry(2)   ! assert  multByTwo(3)  ==  6 Param a is set to 2

Slide 120

Slide 120 text

Closures — partial application 46 def  join  =  {  String  left,  String  sep,  String  right  -­‐>          left  +  sep  +  right   }   ! def  prefix  =  join.curry("Groovy")   assert  prefix("  is  ",  "cool")  ==  "Groovy  is  cool"   ! def  suffix  =  join.rcurry("cool")   assert  suffix("Functional",  "  is  ")  ==  "Functional  is  cool"   ! def  amperJoin  =  join.ncurry(1,  "  &  ")   assert  amperJoin("Marion",  "Érine")  ==  "Marion  &  Érine"

Slide 121

Slide 121 text

Closures — partial application 46 def  join  =  {  String  left,  String  sep,  String  right  -­‐>          left  +  sep  +  right   }   ! def  prefix  =  join.curry("Groovy")   assert  prefix("  is  ",  "cool")  ==  "Groovy  is  cool"   ! def  suffix  =  join.rcurry("cool")   assert  suffix("Functional",  "  is  ")  ==  "Functional  is  cool"   ! def  amperJoin  =  join.ncurry(1,  "  &  ")   assert  amperJoin("Marion",  "Érine")  ==  "Marion  &  Érine" Left curry by default

Slide 122

Slide 122 text

Closures — partial application 46 def  join  =  {  String  left,  String  sep,  String  right  -­‐>          left  +  sep  +  right   }   ! def  prefix  =  join.curry("Groovy")   assert  prefix("  is  ",  "cool")  ==  "Groovy  is  cool"   ! def  suffix  =  join.rcurry("cool")   assert  suffix("Functional",  "  is  ")  ==  "Functional  is  cool"   ! def  amperJoin  =  join.ncurry(1,  "  &  ")   assert  amperJoin("Marion",  "Érine")  ==  "Marion  &  Érine" Left curry by default Right curry

Slide 123

Slide 123 text

Closures — partial application 46 def  join  =  {  String  left,  String  sep,  String  right  -­‐>          left  +  sep  +  right   }   ! def  prefix  =  join.curry("Groovy")   assert  prefix("  is  ",  "cool")  ==  "Groovy  is  cool"   ! def  suffix  =  join.rcurry("cool")   assert  suffix("Functional",  "  is  ")  ==  "Functional  is  cool"   ! def  amperJoin  =  join.ncurry(1,  "  &  ")   assert  amperJoin("Marion",  "Érine")  ==  "Marion  &  Érine" Left curry by default Right curry Curry n-th argument

Slide 124

Slide 124 text

No content

Slide 125

Slide 125 text

Composition

Slide 126

Slide 126 text

Closures — composition 48

Slide 127

Slide 127 text

Closures — composition 48 def  plus2    =  {  it  +  2  }
 def  times3  =  {  it  *  3  }

Slide 128

Slide 128 text

Closures — composition 48 def  plus2    =  {  it  +  2  }
 def  times3  =  {  it  *  3  }

Slide 129

Slide 129 text

Closures — composition 48 def  plus2    =  {  it  +  2  }
 def  times3  =  {  it  *  3  } def  times3plus2  =  plus2  <<  times3
 assert  times3plus2(3)  ==  11
 assert  times3plus2(4)  ==  plus2(times3(4))

Slide 130

Slide 130 text

Closures — composition 48 def  plus2    =  {  it  +  2  }
 def  times3  =  {  it  *  3  } def  times3plus2  =  plus2  <<  times3
 assert  times3plus2(3)  ==  11
 assert  times3plus2(4)  ==  plus2(times3(4))

Slide 131

Slide 131 text

Closures — composition 48 def  plus2    =  {  it  +  2  }
 def  times3  =  {  it  *  3  } def  times3plus2  =  plus2  <<  times3
 assert  times3plus2(3)  ==  11
 assert  times3plus2(4)  ==  plus2(times3(4)) def  plus2times3  =  times3  <<  plus2
 assert  plus2times3(3)  ==  15
 assert  plus2times3(5)  ==  times3(plus2(5))

Slide 132

Slide 132 text

Closures — composition 48 def  plus2    =  {  it  +  2  }
 def  times3  =  {  it  *  3  } def  times3plus2  =  plus2  <<  times3
 assert  times3plus2(3)  ==  11
 assert  times3plus2(4)  ==  plus2(times3(4)) def  plus2times3  =  times3  <<  plus2
 assert  plus2times3(3)  ==  15
 assert  plus2times3(5)  ==  times3(plus2(5))

Slide 133

Slide 133 text

Closures — composition 48 def  plus2    =  {  it  +  2  }
 def  times3  =  {  it  *  3  } def  times3plus2  =  plus2  <<  times3
 assert  times3plus2(3)  ==  11
 assert  times3plus2(4)  ==  plus2(times3(4)) def  plus2times3  =  times3  <<  plus2
 assert  plus2times3(3)  ==  15
 assert  plus2times3(5)  ==  times3(plus2(5)) assert  times3plus2(3)  ==  (times3  >>  plus2)(3)

Slide 134

Slide 134 text

Closures — composition 48 def  plus2    =  {  it  +  2  }
 def  times3  =  {  it  *  3  } def  times3plus2  =  plus2  <<  times3
 assert  times3plus2(3)  ==  11
 assert  times3plus2(4)  ==  plus2(times3(4)) def  plus2times3  =  times3  <<  plus2
 assert  plus2times3(3)  ==  15
 assert  plus2times3(5)  ==  times3(plus2(5)) assert  times3plus2(3)  ==  (times3  >>  plus2)(3) Reverse composition

Slide 135

Slide 135 text

No content

Slide 136

Slide 136 text

Tail recursion!

Slide 137

Slide 137 text

Closures — recursion 50 def  naiveFact  =  {  n  -­‐>          if  (n  <  2)  n          else  n  *  call(n  -­‐  1)   }   ! assert  naiveFact(10)  ==  3628800

Slide 138

Slide 138 text

Closures — recursion 50 def  naiveFact  =  {  n  -­‐>          if  (n  <  2)  n          else  n  *  call(n  -­‐  1)   }   ! assert  naiveFact(10)  ==  3628800 What about naiveFact(1000)?

Slide 139

Slide 139 text

Closures — recursion 50 def  naiveFact  =  {  n  -­‐>          if  (n  <  2)  n          else  n  *  call(n  -­‐  1)   }   ! assert  naiveFact(10)  ==  3628800 What about naiveFact(1000)?

Slide 140

Slide 140 text

No content

Slide 141

Slide 141 text

Trampoline!

Slide 142

Slide 142 text

Closures — recursion with trampoline 52 def  fact  =  {  n,  accu  =  1G  -­‐>          if  (n  <  2)  accu          if  fact.trampoline(n  -­‐  1,  n  *  accu)   }.trampoline()   ! assert  fact(1)        ==  1
 assert  fact(3)        ==  1  *  2  *  3   assert  fact(1000)  ==  402387260...
 //  plus  another  2560  digits

Slide 143

Slide 143 text

Closures — recursion with trampoline 52 def  fact  =  {  n,  accu  =  1G  -­‐>          if  (n  <  2)  accu          if  fact.trampoline(n  -­‐  1,  n  *  accu)   }.trampoline()   ! assert  fact(1)        ==  1
 assert  fact(3)        ==  1  *  2  *  3   assert  fact(1000)  ==  402387260...
 //  plus  another  2560  digits Not so elegant, needs rewriting

Slide 144

Slide 144 text

Closures — @TailRecursive 53 @groovy.transform.TailRecursive   def  fact(n,  accu  =  1G)  {          if  (n  <  2)  accu          else  fact(n  -­‐  1,  n  *  accu)   }

Slide 145

Slide 145 text

Closures — @TailRecursive 53 @groovy.transform.TailRecursive   def  fact(n,  accu  =  1G)  {          if  (n  <  2)  accu          else  fact(n  -­‐  1,  n  *  accu)   } Since Groovy 2.3

Slide 146

Slide 146 text

Closures — @TailRecursive 53 @groovy.transform.TailRecursive   def  fact(n,  accu  =  1G)  {          if  (n  <  2)  accu          else  fact(n  -­‐  1,  n  *  accu)   } Since Groovy 2.3 Transformation applied to methods, not closures

Slide 147

Slide 147 text

Closures — Memoization 54 def  plus  =  {  a,  b  -­‐>  
        sleep  1000
        return  a  +  b     }.memoize()   ! assert  plus(1,  2)  ==  3  //  after  1000ms   assert  plus(1,  2)  ==  3  //  return  immediately   assert  plus(2,  2)  ==  4  //  after  1000ms   assert  plus(2,  2)  ==  4  //  return  immediately

Slide 148

Slide 148 text

Closures — Memoization 54 def  plus  =  {  a,  b  -­‐>  
        sleep  1000
        return  a  +  b     }.memoize()   ! assert  plus(1,  2)  ==  3  //  after  1000ms   assert  plus(1,  2)  ==  3  //  return  immediately   assert  plus(2,  2)  ==  4  //  after  1000ms   assert  plus(2,  2)  ==  4  //  return  immediately Also: memoizeAtLeast(10) memoizeAtMost(20) memoizeBetween(10, 20)

Slide 149

Slide 149 text

Closures — Memoization • Cache the result of previous invocations of closures or methods with the same set 
 of argument values 55 def  fib  =  {  n  -­‐>          if  (n  <  2)  1          else  call(n  -­‐  1)  +  call(n  -­‐  2)   }.memoize()   ! assert  fib(10)  ==  89

Slide 150

Slide 150 text

No content

Slide 151

Slide 151 text

Compile-time meta-programming to the rescue!

Slide 152

Slide 152 text

Memoization 57 import  groovy.transform.*   ! @Memoized   long  fib(long  n)  {          if  (n  <  2)  1          else  fib(n  -­‐  1)  +  fib(n  -­‐  2)   }   ! println  fib(40)

Slide 153

Slide 153 text

Memoization 57 import  groovy.transform.*   ! @Memoized   long  fib(long  n)  {          if  (n  <  2)  1          else  fib(n  -­‐  1)  +  fib(n  -­‐  2)   }   ! println  fib(40) Best applied to side-effect free functions

Slide 154

Slide 154 text

def  list  =  [1,  3,  5,  7]
                      .asImmutable()   ! list  <<  9

Slide 155

Slide 155 text

Immutability is good! def  list  =  [1,  3,  5,  7]
                      .asImmutable()   ! list  <<  9

Slide 156

Slide 156 text

Immutability is good! def  list  =  [1,  3,  5,  7]
                      .asImmutable()   ! list  <<  9 Throws UnsupportedOperationException

Slide 157

Slide 157 text

Immutability is good! def  list  =  [1,  3,  5,  7]
                      .asImmutable()   ! list  <<  9 Throws UnsupportedOperationException Easier to reason about Only one state Can be shared in parallel Suitable for caching ....

Slide 158

Slide 158 text

Immutability is good! def  list  =  [1,  3,  5,  7]
                      .asImmutable()   ! list  <<  9 Throws UnsupportedOperationException Easier to reason about Only one state Can be shared in parallel Suitable for caching .... What about immutable POJOs/POGOs?

Slide 159

Slide 159 text

Immutability • Implement immutability 
 by the book ! – final class – tuple-style constructor – private final backing fields – defensive copying of collections – equals() and hashCode() methods – toString() method – ... 59

Slide 160

Slide 160 text

Immutability • Implement immutability 
 by the book ! – final class – tuple-style constructor – private final backing fields – defensive copying of collections – equals() and hashCode() methods – toString() method – ... 59 Can be error-prone to write immutable classes oneself!

Slide 161

Slide 161 text

Immutability • A Person class with – a String name – an int age 60 public final class Person {! private final String name;! private final int age;! ! public Person(String name, int age) {! this.name = name;! this.age = age;! }! ! public String getName() {! return name;! }! ! public int getAge() {! return age;! }! ! public int hashCode() {! return age + 31 * name.hashCode();! }! ! public boolean equals(Object other) {! if (other == null) {! return false;! }! if (this == other) {! return true;! }! if (Person.class != other.getClass()) {! return false;! }! Person otherPerson = (Person)other;! if (!name.equals(otherPerson.getName()) {! return false;! }! if (age != otherPerson.getAge()) {! return false;! }! return true;! }! ! public String toString() {! return "Person(" + name + ", " + age + ")";! }! }!

Slide 162

Slide 162 text

Immutability • A Person class with – a String name – an int age 60 public final class Person {! private final String name;! private final int age;! ! public Person(String name, int age) {! this.name = name;! this.age = age;! }! ! public String getName() {! return name;! }! ! public int getAge() {! return age;! }! ! public int hashCode() {! return age + 31 * name.hashCode();! }! ! public boolean equals(Object other) {! if (other == null) {! return false;! }! if (this == other) {! return true;! }! if (Person.class != other.getClass()) {! return false;! }! Person otherPerson = (Person)other;! if (!name.equals(otherPerson.getName()) {! return false;! }! if (age != otherPerson.getAge()) {! return false;! }! return true;! }! ! public String toString() {! return "Person(" + name + ", " + age + ")";! }! }! Damn verbose Java!

Slide 163

Slide 163 text

Immutability • A Person class with – a String name – an int age 60 public final class Person {! private final String name;! private final int age;! ! public Person(String name, int age) {! this.name = name;! this.age = age;! }! ! public String getName() {! return name;! }! ! public int getAge() {! return age;! }! ! public int hashCode() {! return age + 31 * name.hashCode();! }! ! public boolean equals(Object other) {! if (other == null) {! return false;! }! if (this == other) {! return true;! }! if (Person.class != other.getClass()) {! return false;! }! Person otherPerson = (Person)other;! if (!name.equals(otherPerson.getName()) {! return false;! }! if (age != otherPerson.getAge()) {! return false;! }! return true;! }! ! public String toString() {! return "Person(" + name + ", " + age + ")";! }! }! Damn verbose Java! Although it’s also a valid Groovy program!

Slide 164

Slide 164 text

@Immutable 61 import  groovy.transform.*   ! @Immutable   class  Person  {          String  name          int  age   }

Slide 165

Slide 165 text

No content

Slide 166

Slide 166 text

Groovy allows you to be lazy

Slide 167

Slide 167 text

Groovy allows you to be lazy The compiler will do the job for you

Slide 168

Slide 168 text

Groovy allows you to be lazy The compiler will do the job for you More concise, more readable code

Slide 169

Slide 169 text

Groovy allows you to be lazy The compiler will do the job for you More concise, more readable code Less stuff to maintain and worry about

Slide 170

Slide 170 text

No content

Slide 171

Slide 171 text

Speaking of laziness...

Slide 172

Slide 172 text

@Lazy 64 class  CountryCodes  {          private  @Lazy  String[]  codes  =                                      ['FR',  'US',  'GB',  /*...*/]   }   ! class  Portfolio  {          @Lazy  List  positions  =  {                  //  fetch  positions  lazily  from  a  DB          }()   }

Slide 173

Slide 173 text

@Lazy 64 class  CountryCodes  {          private  @Lazy  String[]  codes  =                                      ['FR',  'US',  'GB',  /*...*/]   }   ! class  Portfolio  {          @Lazy  List  positions  =  {                  //  fetch  positions  lazily  from  a  DB          }()   } Lazily allocate and create some collection

Slide 174

Slide 174 text

@Lazy 64 class  CountryCodes  {          private  @Lazy  String[]  codes  =                                      ['FR',  'US',  'GB',  /*...*/]   }   ! class  Portfolio  {          @Lazy  List  positions  =  {                  //  fetch  positions  lazily  from  a  DB          }()   } Lazily allocate and create some collection A lazy computation for an expensive structure with closure logic

Slide 175

Slide 175 text

Groovy-stream library 65 @Grab('com.bloidonia:groovy-­‐stream:0.5.2')   import  groovy.stream.Stream   ! def  integers  =  Stream.from  {  x++  }  using  x:  1   def  squares    =  Stream.from  integers  map  {  it  *  it  }   def  first5      =  squares.take(  5  ).collect()   ! assert  first5  ==  [  1,  4,  9,  16,  25  ]   ! def  s  =  Stream.from(  x:1..5,  y:1..3  )                              .filter  {  (x  +  y)  %  (x  +  2)  ==  0  }                              .map  {  x  +  y  }   ! assert  s.collect()  ==  [  3,  4,  5,  6,  7  ]

Slide 176

Slide 176 text

Groovy-stream library 65 @Grab('com.bloidonia:groovy-­‐stream:0.5.2')   import  groovy.stream.Stream   ! def  integers  =  Stream.from  {  x++  }  using  x:  1   def  squares    =  Stream.from  integers  map  {  it  *  it  }   def  first5      =  squares.take(  5  ).collect()   ! assert  first5  ==  [  1,  4,  9,  16,  25  ]   ! def  s  =  Stream.from(  x:1..5,  y:1..3  )                              .filter  {  (x  +  y)  %  (x  +  2)  ==  0  }                              .map  {  x  +  y  }   ! assert  s.collect()  ==  [  3,  4,  5,  6,  7  ] Lazy streams and comprehensions

Slide 177

Slide 177 text

A few other AST transformations • @Delegate – implement the delegate design pattern ! • @Canonical – like @Immutable but for mutable data – combines the @TupleConstructor, @EqualsAndHashcode, and @ToString transformations ! • @Singleton – to create singleton objects (potentially lazily) 66

Slide 178

Slide 178 text

Persistent data structures • No built-in persistent collections — yet ! • But works well with existing – Functional Java – pcollections – clj-ds – totallylazy 67

Slide 179

Slide 179 text

Persistent data structures 68

Slide 180

Slide 180 text

Persistent data structures 68 @Grab("org.pcollections:pcollections:2.1.2")
 import  org.pcollections.*

Slide 181

Slide 181 text

Persistent data structures 68 @Grab("org.pcollections:pcollections:2.1.2")
 import  org.pcollections.*

Slide 182

Slide 182 text

Persistent data structures 68 @Grab("org.pcollections:pcollections:2.1.2")
 import  org.pcollections.* def  m0  =  HashTreePMap.from(a:  1,  b:  2)
 assert  m0.size()  ==  2

Slide 183

Slide 183 text

Persistent data structures 68 @Grab("org.pcollections:pcollections:2.1.2")
 import  org.pcollections.* def  m0  =  HashTreePMap.from(a:  1,  b:  2)
 assert  m0.size()  ==  2

Slide 184

Slide 184 text

Persistent data structures 68 @Grab("org.pcollections:pcollections:2.1.2")
 import  org.pcollections.* def  m0  =  HashTreePMap.from(a:  1,  b:  2)
 assert  m0.size()  ==  2 def  m1  =  m0  +  [c:  3]
 assert  m1.size()  ==  3  &&  m1.c  ==  3
 assert  m0.size()  ==  2

Slide 185

Slide 185 text

Persistent data structures 68 @Grab("org.pcollections:pcollections:2.1.2")
 import  org.pcollections.* def  m0  =  HashTreePMap.from(a:  1,  b:  2)
 assert  m0.size()  ==  2 def  m1  =  m0  +  [c:  3]
 assert  m1.size()  ==  3  &&  m1.c  ==  3
 assert  m0.size()  ==  2

Slide 186

Slide 186 text

Persistent data structures 68 @Grab("org.pcollections:pcollections:2.1.2")
 import  org.pcollections.* def  m0  =  HashTreePMap.from(a:  1,  b:  2)
 assert  m0.size()  ==  2 def  m1  =  m0  +  [c:  3]
 assert  m1.size()  ==  3  &&  m1.c  ==  3
 assert  m0.size()  ==  2 def  m2  =  m0  -­‐  'a'
 assert  m0.size()  ==  2
 assert  m1.size()  ==  3
 assert  m2.size()  ==  1

Slide 187

Slide 187 text

No content

Slide 188

Slide 188 text

That’s probably the part of the talk where you’d need a brain

Slide 189

Slide 189 text

That’s probably the part of the talk where you’d need a brain But I don’t have one

Slide 190

Slide 190 text

Monads, Functors, Option, Either… • Groovy doesn’t come built-in with monads, option, either, comprehensions, but third-party libraries bring that support ! – Monadologie – Fpiglet – Functional Groovy 70

Slide 191

Slide 191 text

Monads, Functors, Option, Either… • Groovy doesn’t come built-in with monads, option, either, comprehensions, but third-party libraries bring that support ! – Monadologie – Fpiglet – Functional Groovy 70 References available in the «resources» part

Slide 192

Slide 192 text

ForEach monad comprehension 71 import  static          hr.helix.monadologie.MonadComprehension.foreach   ! def  res  =  foreach  {          a  =  takeFrom  {  [1,  2,  3]  }          b  =  takeFrom  {  [4,  5]  }   !        yield  {  a  +  b  }   }   ! assert  res  ==  [5,  6,  6,  7,  7,  8]

Slide 193

Slide 193 text

Part 4 Summary

Slide 194

Slide 194 text

No content

Slide 195

Slide 195 text

I’m functional!

Slide 196

Slide 196 text

Part 5 Resources

Slide 197

Slide 197 text

• Paul King – Concurrency with GPars • http://slideshare.net/paulk_asert/concurrency-gpars – Functional Groovy • http://slideshare.net/paulk_asert/functional-groovy • Andres Almiray – Functional Groovy • http://slideshare.net/aalmiray/functional-groovy-confess • Arturo Herrero – Functional programming with Groovy • http://slideshare.net/arturoherrero/functional-programming-with-groovy • Neal Ford – Functional thinking • http://www.youtube.com/watch?v=7aYS9PcAITQ&feature=youtu.be • Mario Fusco – If you think you can stay away from FP, you are wrong • http://slideshare.net/mariofusco/if-you-think-you-can-stay-away-from-functional-programming-you-are-wrong Resources — Presentations 75

Slide 198

Slide 198 text

Resources — Interesting projects • GPars — Concurrency & parallelism library – http://gpars.codehaus.org/ • Fpiglet — Blog post experiments on combinators, monadic comprehensions – https://code.google.com/p/fpiglet/ – http://rpeszek.blogspot.ch/ • Monadologie — Monad comprehensions library – https://github.com/dsrkoc/monadologie • Groovy Stream — Lazy iterators and streams – http://timyates.github.io/groovy-stream/ • Functional Groovy — Functional Java wrapper – https://github.com/mperry/functionalgroovy 76

Slide 199

Slide 199 text

Thank you! Q&A