Functional Programming with Groovy
Prochain SlideShare
Chargement dans... 5
×

Vous aimez ? Partagez donc ce contenu avec votre réseau

Partager

Functional Programming with Groovy

  • 12,373 vues
Transféré le

My talk about Functional Programming with Groovy at Greach ...

My talk about Functional Programming with Groovy at Greach

Greach http://greach.es/
the Groovy spanish conf
Date:
04-11-2011

  • Full Name Full Name Comment goes here.
    Êtes-vous sûr de vouloir
    Votre message apparaîtra ici
Aucun téléchargement

Vues

Total des vues
12,373
Sur Slideshare
8,181
À partir des ajouts
4,192
Nombre d'ajouts
17

Actions

Partages
Téléchargements
141
Commentaires
1
J'aime
12

Ajouts 4,192

http://arturoherrero.com 2,962
http://mindfood.osoco.es 762
http://localhost 197
http://greach.es 125
http://lanyrd.com 42
http://mindfood.tumblr.com 36
https://twitter.com 17
http://abtasty.com 16
http://a0.twimg.com 16
http://www.tumblr.com 5
http://127.0.0.1 4
http://inoreader.com 3
https://si0.twimg.com 2
http://translate.googleusercontent.com 2
https://service.madeira20.com 1
http://digg.com 1
https://www.google.es 1

Signaler un contenu

Signalé comme inapproprié Signaler comme inapproprié
Signaler comme inapproprié

Indiquez la raison pour laquelle vous avez signalé cette présentation comme n'étant pas appropriée.

Annuler
    No notes for slide

Transcript

  • 1. Functional Programming with Groovλ
  • 2. @ArturoHerrerohttp://arturoherrero.com
  • 3. Working at OSOCOSmall but outstanding software development shop Groovy and Grails hackers on EC2 cloud nine TDD mantra singers Quality preachers
  • 4. LISt Processing (define (factorial n) (if (= n 1) 1 (* n (factorial (- n 1)))))
  • 5. Lots of Insipid Stupid Parentheses ( (factorial ) ( ( ) ( (factorial ( )))))
  • 6. Code CompleteThe Pragmatic ProgrammerStructure and Interpretation of Computer Programs
  • 7. A language that doesnt affect the way you think about programming, is not worth knowing Alan Perlis
  • 8. Functional Programming
  • 9. Function
  • 10. Functional Programming Avoiding Mutable Stateλ Side-Effect-Free Functionsλ Referential Transparencyλ First-Class Citizensλ Higher-Order Functionsλ Lambdas and Closuresλ Lazy Evaluationλ Recursionλ
  • 11. Why Functional Programming? Referential transparencyλ Unit testingλ Debbugingλ Parallelizationλ Modularity and compositionλ Increases the quality of codeλ Abstractionsλ
  • 12. OOP vs. FP
  • 13. Imperative vs. DeclarativeImperative: how to achieve our goal Take the next customer from a list. If the customer lives in Spain, show their details. If there are more customers in the list, go to the beginningDeclarative: what we want to achieve Show customer details of every customer living in Spain
  • 14. Imperative vs. DeclarativeFunctional programming is like describing your problem to a mathematician. Imperative programming is like giving instructions to an idiot. arcus, #scheme on Freenode
  • 15. Functional Programmingwith Groovy? is an imperative language,but we still can apply functional principles Its basically a programmers choice
  • 16. ImmutabilitySimple Immutable objects can only be in exactly one state, the state in which it was createdAlways consistent Less prone to errors and more secureImmutable objects can be shared freely Freedom to cacheInherently thread-safe
  • 17. ImmutabilityNO: (even being a name rebind and not a real update)book = Fooled by Randomnessbook = "$book - Nassim Taleb"book = "$book (2001)"assert Fooled by Randomness - Nassim Taleb (2001) == bookYES:book = Fooled by RandomnessbookWithAuthor = "$book - Nassim Taleb"completeBook = "$bookWithAuthor (2001)"assert Fooled by Randomness - Nassim Taleb (2001) == completeBook
  • 18. ImmutabilityNO:years = [2001, 2002]years << 2003years += [2004, 2005]assert [2001, 2002, 2003, 2004, 2005] == yearsYES:years = [2001, 2002]allYears = years + 2003 + [2004, 2005]assert [2001, 2002, 2003, 2004, 2005] == allYears
  • 19. Immutabilitydef list = [Gr, vy]NO:list.addAll 1, ooassert list == [Gr, oo, vy]YES:assert list.plus(1, oo) == [Gr, oo, vy]assert list == [Gr, vy]
  • 20. Immutabilitydef list = [1, 2, 2, 3]NO:list.removeAll 2assert list == [1, 3]YES:assert list.minus(2) == [1, 3]assert list == [1, 2, 2, 3]
  • 21. Immutabilitydef list = [Scala, Groovy, Java]NO:sortedList = list.sort()assert sortedList == [Groovy, Java, Scala]assert list == [Groovy, Java, Scala]YES:sortedList = list.sort(false)assert sortedList == [Groovy, Java, Scala]assert list == [Scala, Groovy, Java]
  • 22. Immutabilitydef list = [Java, Groovy, Java]NO:uniqueList = list.unique()assert uniqueList == [Java, Groovy]assert list == [Java, Groovy]YES:uniqueList = list.unique(false)assert uniqueList == [Java, Groovy]assert list == [Java, Groovy, Java]
  • 23. Immutabilitydef list = [Java, Groovy]NO:reverseList = list.reverse(true)assert reverseList == [Groovy, Java]assert list == [Groovy, Java]YES:reverseList = list.reverse()assert reverseList == [Groovy, Java]assert list == [Java, Groovy]
  • 24. Immutability Collectiondef list = [Groovy, Java].asImmutable()assert Groovy == list.first()try { list.add Scala // Cannot add item} catch (e) { assert e instanceof UnsupportedOperationException}try { list.remove Java // Cannot remove item} catch (e) { assert e instanceof UnsupportedOperationException}
  • 25. Immutability Class@Immutable class Coordinates { Double latitude, longitude}def c1 = new Coordinates(latitude: 48.824068, longitude: 2.531733)def c2 = new Coordinates(48.824068, 2.531733)assert c1 == c2
  • 26. Higher-Order FunctionsFirst-Class Citizen Can be stored in variables Can be passed as function parameter Can be returned from functionsHigher-Order Functions (First-Class Functions) Functions that take other functions as arguments or return them as results
  • 27. Closuresdef closure = { Hello world! }assert closure() == Hello world!def sum = { a, b -> a + b }assert sum(2,3) == 5def square = { it * it }assert square(9) == 81final BASE = 1000def salary = { variable -> BASE + variable }assert salary(500) == 1500
  • 28. Turn Methods into Closuresdef salary(variable) { final BASE = 1000 BASE + variable}assert salary(500) == 1500def salaryClosure = this.&salaryassert salaryClosure(500) == 1500
  • 29. Closures Compositiondef minutesToSeconds = { it * 60 }def hoursToMinutes = { it * 60 }def daysToHours = { it * 24 }def hoursToSeconds = minutesToSeconds << hoursToMinutesdef daysToSeconds = hoursToSeconds << daysToHoursassert daysToSeconds(1) == 86400
  • 30. Closures Compositiondef upper = { it.toUpperCase() }def firstLetter = { it.charAt(0) }def words = ["Dont", "Repeat", "Yourself"]def acronym = words.collect(firstLetter >> upper).join()assert acronym == DRY
  • 31. Curryinggiven: ƒ: (X x Y) -> Zthen: curry(ƒ): X -> (Y -> Z) Takes a function with a particular number of parameters and returns a function with some of the parameter values fixed, creating a new function
  • 32. Curryingdef modulus = { mod, num -> num % mod}assert modulus(2, 5) == 1assert modulus(3, 5) == 2def mod2 = modulus.curry(2)assert mod2(5) == 1def mod3 = modulus.curry(3)assert mod3(5) == 2
  • 33. Curryingdef bill = { amount, currency -> "$amount $currency"}assert bill(1000, $) == 1000 $assert bill(1000, €) == 1000 €def billInDollars = bill.rcurry($)assert billInDollars(1000) == 1000 $def billInEuros = bill.rcurry(€)assert billInEuros(1000) == 1000 €
  • 34. Curryingdef joinWithSeparator = { one, sep, two -> one + sep + two}def joinWithAmpersand = joinWithSeparator.ncurry(1, &)assert joinWithAmpersand(a, b) == a&b
  • 35. Classic Operations onFunctional Data Types list filter map fold
  • 36. Classic Operations onFunctional Data Types list findAll collect inject
  • 37. Classic Operations onFunctional Data Types list any every sort min sum
  • 38. findAll()NO:def result = [][1, 2, 3, 4].each { if (it > 2) { result << it }}assert result == [3, 4]YES:assert [1, 2, 3, 4].findAll{ it > 2 } == [3, 4]
  • 39. collect()NO:def result = [][1, 2, 3].each { result << it * 2}assert result == [2, 4, 6]YES:assert [1, 2, 3].collect{ it * 2 } == [2, 4, 6]
  • 40. inject()NO:def total = 0[1, 2, 3].each { total += it}assert total == 6YES:def total = [1, 2, 3].inject(0) { acc, n -> acc + n}assert total == 6
  • 41. find()NO:def resulttry { [1, 2, 3].each { if (it > 1) { result = it throw new Exception() // monstrous } }} catch(exception) { }assert result == 2YES:assert [1, 2, 3].find{ it > 1 } == 2
  • 42. max()@TupleConstructor // import groovy.transform.*class Person { String name Integer age}def person1 = new Person(Arturo, 26)def person2 = new Person(Luis, 61)def person3 = new Person(Laura, 19)def family = [] << person1 << person2 << person3assert family.max{ it.age }.age == 61assert family.collect{ it.age }.max() == 61assert family*.age.max() == 61
  • 43. Refactoringdef exists = falsefamily.each { person -> if (person.age > 60) { exists = true }}assert exists == truedef exists = family.inject(false) { found, person -> if (person.age > 60) { found = true } return found}assert exists == trueassert family.any{ it.age > 60 } == true
  • 44. Combinator Functions@TupleConstructor // import groovy.transform.*class Person { String name String lastname Integer age}def rafa = new Person(Rafael, Luque, 36)def marcin = new Person(Marcin, Gryszko, 34)def arturo = new Person(Arturo, Herrero, 26)def osokers = [] << rafa << marcin << arturo << rafaassert osokers.unique(false) .findAll{ it.age > 30} .sort{ it.lastname } == [marcin, rafa]assert osokers == [rafa, marcin, arturo, rafa]
  • 45. Combinator Functions// Procedural styledef count = 0for (i in (1 .. 1000)) { if (i % 2) { count += ("$i".size()) }}assert count == 1445// Functional styledef count = (1 .. 1000).findAll{ it % 2 } .collect{ "$it" } .inject(0) { sum, num -> sum + num.size() }assert count == 1445
  • 46. Lazy EvaluationOnly does as much work as necessary Delays the evaluation of the expression until its neededCPU efficient The value is not calculated or assigned until the value is requestedManage potentially infinite data structures Only a manageable subset of the data will actually be used
  • 47. Lazy Evaluationclass Person { @Lazy String name = Arturo}def person = new Person()assert !(person.dump().contains(Arturo))assert person.name.size() == 6assert person.dump().contains(Arturo)
  • 48. Lazy Evaluationclass Get { String url @Lazy URL urlObj = { url?.toURL() }() @Lazy(soft=true) String text = urlObj?.text}def get = new Get(url: http://arturoherrero.com)assert get.url == http://arturoherrero.comassert get.dump().contains(text=null)assert get.dump().contains(urlObj=null)assert get.urlObj.protocol == httpassert get.urlObj.host == arturoherrero.comassert get.text.contains(Arturo Herrero)
  • 49. Lazy Evaluationgroovy.sql.DataSet.DataSetgroovy.util.XmlSlurper@Singleton(lazy=true)class Util { Integer count(text) { text.size() }}assert 6 == Util.instance.count(Arturo)
  • 50. Infinite structuresclass LazyList { ...}def naturalnumbers = integers(1)assert 1 2 3 4 5 6 == naturalnumbers.take(6).join( )def evennumbers = naturalnumbers.filter{ it % 2 == 0 }assert 2 4 6 8 10 12 == evennumbers.take(6).join( )
  • 51. Infinite structures@Grab(org.functionaljava:functionaljava:3.0)import fj.data.StreamStream.metaClass.filter = { Closure c -> delegate.filter(c as fj.F) }Stream.metaClass.asList = { delegate.toCollection().asList() }def evens = Stream.range(1).filter{ it % 2 == 0 }assert [2, 4, 6, 8, 10, 12] == evens.take(6).asList()
  • 52. Recursivefactorial(6)6 * factorial(5)6 * (5 * factorial(4))6 * (5 * (4 * factorial(3)))6 * (5 * (4 * (3 * factorial(2))))6 * (5 * (4 * (3 * (2 * factorial(1)))))6 * (5 * (4 * (3 * (2 * 1))))6 * (5 * (4 * (3 * 2)))6 * (5 * (4 * 6))6 * (5 * 24)6 * 120720
  • 53. Recursivefactorial(6)6 * factorial(5)6 * (5 * factorial(4))6 * (5 * (4 * factorial(3)))6 * (5 * (4 * (3 * factorial(2))))6 * (5 * (4 * (3 * (2 * factorial(1)))))6 * (5 * (4 * (3 * (2 * 1))))6 * (5 * (4 * (3 * 2)))6 * (5 * (4 * 6))6 * (5 * 24)6 * 120720
  • 54. Tail-Recursivefactorial(6, 1)factorial(5, 6)factorial(4, 30)factorial(3, 120)factorial(2, 360)factorial(1, 720)
  • 55. Tail-Recursivefactorial(6, 1)factorial(5, 6)factorial(4, 30)factorial(3, 120)factorial(2, 360)factorial(1, 720)
  • 56. Tail Call Optimization3 techniques: The compiler transform the recursion into a loopλ Let the JVM recognize the recursion and eliminate itλ Transform the recursion into iterative by handλ
  • 57. Tail Call Optimization3 techniques: The compiler transform the recursion into a loopλ Let the JVM recognize the recursion and eliminate itλ Transform the recursion into iterative by handλ really?
  • 58. Tail Call Optimizationdef factorialfactorial = { n -> n == 1 ? 1 : n * factorial(n - 1)}factorial(1000)
  • 59. Tail Call Optimization rflow kO vedef factorial S tacfactorial = { n -> n == 1 ? 1 : n * factorial(n - 1)}factorial(1000)
  • 60. Tail Call Optimizationdef factorialfactorial = { n, BigInteger acc = 1 -> n == 1 ? acc : factorial(n - 1, n * acc)}factorial(1000)
  • 61. Tail Call Optimization rflow kO vedef factorial S tacfactorial = { n, BigInteger acc = 1 -> n == 1 ? acc : factorial(n - 1, n * acc)}factorial(1000)
  • 62. Tail Call Optimizationdef factorialfactorial = { n, BigInteger acc = 1 -> n == 1 ? acc : factorial.trampoline(n - 1, n * acc)}.trampoline()factorial(1000)
  • 63. Trampoliningdef even, oddeven = { x -> x == 0 ? true : odd.trampoline(x - 1) }.trampoline()odd = { x -> x == 0 ? false : even.trampoline(x - 1) }.trampoline()assert even(1000) == true
  • 64. Memoizationdef fibonaccifibonacci = { n -> n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2)}fibonacci(35) // 9.935 seconds
  • 65. Memoizationdef fibonaccifibonacci = { n -> n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2)}.memoize()fibonacci(35) // 0.002 seconds
  • 66. Memoizationdef plus = { a, b -> sleep 1000; a + b }.memoize()assert plus(1, 2) == 3 // after 1000msassert plus(1, 2) == 3 // return immediatelyassert plus(2, 2) == 4 // after 1000msassert plus(2, 2) == 4 // return immediatelydef plusAtLeast = { ... }.memoizeAtLeast(10)def plusAtMost = { ... }.memoizeAtMost(10)def plusBetween = { ... }.memoizeBetween(10, 20)
  • 67. “Functional” is more a way of thinking than a tool set Neal Ford
  • 68. Be a craftsman
  • 69. Thank you!@ArturoHerreroJoin us at OSOCO