Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Discovering Functional Treasure
in
Idiomatic Groovy
Naresha K
Enteleki Solutions
!
naresha.k@gmail.com
@naresha_k
An imperative
language on JVM
A dynamic
with Functional Flavour
The origin
http://radio-weblogs.com/0112098/2003/08/29.html
initial idea was to make a little dynamic language which
compi...
Prerequisites
Function
!
def sayHello(){!
! println 'Hello'!
}!
!
sayHello()!
Closure
def wish = {!
! println "Hello"!
}!
!
wish()
def wishFriend = {!
! println "Hello $it"!
} !
!
wishFriend 'Raj'
def...
Closure - No Arg
def wish = { ->!
! println "Hello"!
}!
!
wish()
Closure - Multiple args
def wishWithMessage = { to, message ->!
! println "Hello $to, $message"!
}!
!
wishWithMessage "Raj...
Closures = Power functions
def wishWithMessage = { to, message ->!
! println "Hello $to, $message"!
}!
!
wishWithMessage "...
Sample Data
import groovy.transform.ToString!
!
@ToString(includeNames=true)!
class Geek{!
String name!
int age!
List<Stri...
Geeks who can speak Groovy
def findGroovyGeeksImperative(geeks){!
! def groovyGeeks = []!
! for(geek in geeks){!
! if(geek...
Geeks who can speak Groovy
def findGroovyGeeksImperative(geeks){!
! def groovyGeeks = []!
! for(geek in geeks){!
! if(geek...
Generalised
def findGeeks(geeks, String language){!
! def knowsLang = []!
! for(geek in geeks){!
! if(geek.languages.conta...
Towards Idiomatic Groovy
def findGroovyGeeksFunctional(geeks){!
! geeks.findAll({it.languages.contains('Groovy')})!
}
def ...
Reusable
def knowsGroovy = { geek -> !
! geek.languages.contains('Groovy')!
}!
!
def findGeeksFunctional(geeks, criterion)...
Strategy Pattern
def knowsGroovy = { geek -> !
! geek.languages.contains('Groovy')!
}!
!
def knowsClojure = { geek ->!
! g...
Command Pattern
def sayHello = {!
! println "Hello"!
}!
!
def sayHi = {!
! println "Hi"!
}!
!
[sayHello, sayHi].each{ comm...
Execute Around
def sayHello = {!
! println "Hello"!
}!
!
def sayHi = {!
! println "Hi"!
}!
!
[sayHello, sayHi].each{ comma...
Code Smell!
def knowsGroovy = { geek -> !
! geek.languages.contains('Groovy')!
}!
!
def knowsClojure = { geek ->!
! geek.l...
After DRYing
def knowsLanguage = { geek, language ->!
! geek.languages.contains(language)!
}!
!
def findGeeks(geeks, crite...
A Better Approach
def knowsLanguage = { geek, language ->!
! geek.languages.contains(language)!
}!
!
def knowsGroovy = kno...
Geeks
• Knows Groovy
• At least 25 years old
Composing em
def atleast25YearsOld = { geek ->!
! geek.age >= 25!
}!
!
def findGeeks(geeks, criterion){!
! geeks.findAll(c...
Towards Immutable Data
def geeks = []!
geeks << new Geek(name: 'Raj', age: 24, !
! languages: ['Java', 'Groovy'])!
geeks <...
Towards Immutable Data …
def geeksOrderedByAge = geeks.sort { it.age }!
println geeksOrderedByAge!
println geeks
def geeks...
Demo
import groovy.transform.*!
!
@TailRecursive!
def factorial(number, fact = 1){!
! number == 0 ? fact : factorial(number - 1...
Prior to Groovy 2.3
def fact!
fact = { number, result ->!
! number == 0 ? result : !
! ! fact.trampoline(number-1, result ...
Slow Functions
import groovy.transform.*!
!
@Memoized!
def timeConsumingOperation(int number){!
! println "Performing computation"!
! num...
Map Filter Reduce
println geeks.findAll { it.languages.contains('Groovy')}!
! ! ! .collect {it.age}!
! ! ! .sum()!
!
print...
Defer
Defer
import groovy.transform.*!
!
class Website{!
! String address!
! @Lazy !
! URL url = address.toURL()!
}!
!
!
def fuc...
Recursion vs Iteration
Recursion vs Iteration
def ages = geeks.collect { it.age }!
!
def sum!
sum = { head, tail ->!
! if(!tail){!
! ! head!
! }!...
Recursion vs Iteration
println ages.inject(0) { s, item ->!
! s + item!
}
The Ultimate Lesson
https://twitter.com/mfeathers/status/29581296216
Functional Treasures
Functions as values (First class citizens)
Higher order functions
Curried Functions
Function Composit...
Welcome to
References
• https://github.com/naresha/functionalconf2014
Discovering functional treasure in idiomatic Groovy
Discovering functional treasure in idiomatic Groovy
Upcoming SlideShare
Loading in …5
×

Discovering functional treasure in idiomatic Groovy

Slides of my talk at Functional Conf 2014 - Oct 9-11, Bangalore

Discovering functional treasure in idiomatic Groovy

  1. 1. Discovering Functional Treasure in Idiomatic Groovy Naresha K Enteleki Solutions ! naresha.k@gmail.com @naresha_k
  2. 2. An imperative language on JVM A dynamic with Functional Flavour
  3. 3. The origin http://radio-weblogs.com/0112098/2003/08/29.html initial idea was to make a little dynamic language which compiles directly to Java classes and provides all the nice (alleged) productivity benefits - James Strachan
  4. 4. Prerequisites
  5. 5. Function ! def sayHello(){! ! println 'Hello'! }! ! sayHello()!
  6. 6. Closure def wish = {! ! println "Hello"! }! ! wish() def wishFriend = {! ! println "Hello $it"! } ! ! wishFriend 'Raj' def wishFriend = { to ->! ! println "Hello $to"! }! ! wishFriend 'Raj'
  7. 7. Closure - No Arg def wish = { ->! ! println "Hello"! }! ! wish()
  8. 8. Closure - Multiple args def wishWithMessage = { to, message ->! ! println "Hello $to, $message"! }! ! wishWithMessage "Raj", "Good Evening"
  9. 9. Closures = Power functions def wishWithMessage = { to, message ->! ! println "Hello $to, $message"! }! ! wishWithMessage "Raj", "Good Evening" def <var> = <closure> Functions as Values
  10. 10. Sample Data import groovy.transform.ToString! ! @ToString(includeNames=true)! class Geek{! String name! int age! List<String> languages! } def geeks = []! geeks << new Geek(name: 'Raj', age: 24, ! ! languages: ['Java', 'Groovy'])! geeks << new Geek(name: 'Arun', age: 35, ! ! languages: ['Java', 'Scala', 'Clojure'])! geeks << new Geek(name: 'Kumar', age: 28, ! ! languages: ['Groovy', 'Scala'])!
  11. 11. Geeks who can speak Groovy def findGroovyGeeksImperative(geeks){! ! def groovyGeeks = []! ! for(geek in geeks){! ! if(geek.languages.contains('Groovy')){! ! groovyGeeks << geek! ! }! ! }! ! groovyGeeks! }
  12. 12. Geeks who can speak Groovy def findGroovyGeeksImperative(geeks){! ! def groovyGeeks = []! ! for(geek in geeks){! ! if(geek.languages.contains('Groovy')){! ! groovyGeeks << geek! ! }! ! }! ! groovyGeeks! }
  13. 13. Generalised def findGeeks(geeks, String language){! ! def knowsLang = []! ! for(geek in geeks){! ! if(geek.languages.contains(language)){! ! knowsLang << geek! ! }! ! }! ! knowsLang! }!
  14. 14. Towards Idiomatic Groovy def findGroovyGeeksFunctional(geeks){! ! geeks.findAll({it.languages.contains('Groovy')})! } def findGroovyGeeksFunctional(geeks){! ! geeks.findAll() {it.languages.contains('Groovy')}! } def findGroovyGeeksFunctional(geeks){! ! geeks.findAll {it.languages.contains('Groovy')}! }
  15. 15. Reusable def knowsGroovy = { geek -> ! ! geek.languages.contains('Groovy')! }! ! def findGeeksFunctional(geeks, criterion){! ! geeks.findAll(criterion)! }! ! println findGeeksFunctional(geeks, knowsGroovy) Higher Order Functions
  16. 16. Strategy Pattern def knowsGroovy = { geek -> ! ! geek.languages.contains('Groovy')! }! ! def knowsClojure = { geek ->! ! geek.languages.contains('Clojure')! }! ! def findGeeksFunctional(geeks, criterion){! ! geeks.findAll(criterion)! }! ! println findGeeksFunctional(geeks, knowsGroovy)! println findGeeksFunctional(geeks, knowsClojure)
  17. 17. Command Pattern def sayHello = {! ! println "Hello"! }! ! def sayHi = {! ! println "Hi"! }! ! [sayHello, sayHi].each{ command ->! ! command()! }
  18. 18. Execute Around def sayHello = {! ! println "Hello"! }! ! def sayHi = {! ! println "Hi"! }! ! [sayHello, sayHi].each{ command ->! ! println "Before Command"! ! command()! ! println "After Command"! }
  19. 19. Code Smell! def knowsGroovy = { geek -> ! ! geek.languages.contains('Groovy')! }! ! def knowsClojure = { geek ->! ! geek.languages.contains('Clojure')! }
  20. 20. After DRYing def knowsLanguage = { geek, language ->! ! geek.languages.contains(language)! }! ! def findGeeks(geeks, criterion, String language){! ! geeks.findAll {criterion(it, language)}! }! ! println findGeeks(geeks, knowsLanguage, 'Groovy')
  21. 21. A Better Approach def knowsLanguage = { geek, language ->! ! geek.languages.contains(language)! }! ! def knowsGroovy = knowsLanguage.rcurry('Groovy')! def knowsClojure = knowsLanguage.rcurry('Clojure')! ! def findGeeks(geeks, criterion){! ! geeks.findAll(criterion)! }! ! println findGeeks(geeks, knowsGroovy)! println findGeeks(geeks, knowsClojure) Curried Functions
  22. 22. Geeks • Knows Groovy • At least 25 years old
  23. 23. Composing em def atleast25YearsOld = { geek ->! ! geek.age >= 25! }! ! def findGeeks(geeks, criterion){! ! geeks.findAll(criterion)! }! ! def findGroovyGeeks = (this.&findGeeks)! ! .rcurry(knowsGroovy)! def findGeeksAtLeast25 = (this.&findGeeks)! ! .rcurry(atleast25YearsOld) def findGroovyGeeksOlderThan24 = ! ! findGeeksAtLeast25 << findGroovyGeeks! ! println findGroovyGeeksOlderThan24(geeks) Function Composition
  24. 24. Towards Immutable Data def geeks = []! geeks << new Geek(name: 'Raj', age: 24, ! ! languages: ['Java', 'Groovy'])! geeks << new Geek(name: 'Arun', age: 35, ! ! languages: ['Java', 'Scala', 'Clojure'])! geeks << new Geek(name: 'Kumar', age: 28, ! ! languages: ['Groovy', 'Scala']) geeks2 = geeks + new Geek(name: 'Mark', age: 40, ! ! languages: ['Lisp', 'Haskell']) geeksImmutable = geeks.asImmutable()
  25. 25. Towards Immutable Data … def geeksOrderedByAge = geeks.sort { it.age }! println geeksOrderedByAge! println geeks def geeksOrderedByAge = geeks.sort false, { it.age }! println geeksOrderedByAge! println geeks Pure Functions
  26. 26. Demo
  27. 27. import groovy.transform.*! ! @TailRecursive! def factorial(number, fact = 1){! ! number == 0 ? fact : factorial(number - 1, fact * number)! }! ! println factorial(2500G) Tail Call Optimization
  28. 28. Prior to Groovy 2.3 def fact! fact = { number, result ->! ! number == 0 ? result : ! ! ! fact.trampoline(number-1, result * number)! }.trampoline()
  29. 29. Slow Functions
  30. 30. import groovy.transform.*! ! @Memoized! def timeConsumingOperation(int number){! ! println "Performing computation"! ! number * number! }! ! println timeConsumingOperation(2)! println timeConsumingOperation(2) Memoization
  31. 31. Map Filter Reduce println geeks.findAll { it.languages.contains('Groovy')}! ! ! ! .collect {it.age}! ! ! ! .sum()! ! println geeks.findAll { it.languages.contains('Groovy')}! ! ! ! .collect {it.age}! ! ! ! .with{ sum()/ size()}
  32. 32. Defer
  33. 33. Defer import groovy.transform.*! ! class Website{! ! String address! ! @Lazy ! ! URL url = address.toURL()! }! ! ! def fuconf = new Website(address: 'http://functionalconf.com/')! println fuconf.dump()! ! def content = fuconf.url.text! println content.grep("n").size()! println fuconf.dump()! Lazy Evaluation
  34. 34. Recursion vs Iteration
  35. 35. Recursion vs Iteration def ages = geeks.collect { it.age }! ! def sum! sum = { head, tail ->! ! if(!tail){! ! ! head! ! }! ! else{! ! ! head + sum(tail.head(), tail.tail())! ! }! }! ! println(sum(0, ages))
  36. 36. Recursion vs Iteration println ages.inject(0) { s, item ->! ! s + item! }
  37. 37. The Ultimate Lesson https://twitter.com/mfeathers/status/29581296216
  38. 38. Functional Treasures Functions as values (First class citizens) Higher order functions Curried Functions Function Composition Pure Functions (Immutability) Tail Call Optimization Memoization Lazy Evaluation
  39. 39. Welcome to
  40. 40. References • https://github.com/naresha/functionalconf2014

×