The document discusses functional programming concepts using Groovy, emphasizing the importance of immutability, higher-order functions, and lazy evaluation. It contrasts functional programming with imperative styles, illustrating how functional approaches can enhance code quality and maintainability. The text provides examples and techniques such as currying, memoization, and tail call optimization to demonstrate functional programming principles in practice.
Introduction to functional programming, particularly with Groovy. Concepts like avoiding mutable state and combining functions are introduced.
Highlights advantages such as referential transparency, unit testing, modularity, and improved code quality.
Contrasts Object-Oriented Programming (OOP) with Functional Programming (FP) and explains the distinction between imperative and declarative programming.
Discusses how Groovy, while imperative, can implement functional programming principles based on programmer preference.
Explains immutability in programming, showcasing examples of mutable and immutable states with Groovy collections.
Describes higher-order functions as first-class citizens, encouraging functional programming practices in variable storage and parameter passing.
Discusses closures with practical examples including closure composition and function transformation.
Explains currying, demonstrating how functions can be transformed and reused with partial application.
Outlines common operations like mapping, filtering, and injecting on functional data required for Groovy classes.
Demonstrates practical applications of finding, collecting, and injecting values in arrays.
Introduces lazy evaluation, which optimizes memory usage and CPU efficiency by delaying computation.
Illustrates handling of infinite data structures and functional programming tools to manipulate such collections.
Explains recursive function development with factorial examples, emphasizing tail recursion for optimization.
Describes various techniques for optimizing tail calls, ensuring efficient recursive function execution.
Discusses memoization techniques to enhance function performance, aided by practical examples.
Encourages mastery of functional programming, emphasizing craft and thanking the audience for participation.
Imperative vs. Declarative Imperative: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 beginning Declarative: what we want to achieve Show customer details of every customer living in Spain
15.
Imperative vs. Declarative Functionalprogramming is like describing your problem to a mathematician. Imperative programming is like giving instructions to an idiot. arcus, #scheme on Freenode
16.
Functional Programming with Groovy? is an imperative language, but we still can apply functional principles It's basically a programmer's choice
17.
Immutability Simple Immutableobjects can only be in exactly one state, the state in which it was created Always consistent Less prone to errors and more secure Immutable objects can be shared freely Freedom to cache Inherently thread-safe
18.
Immutability NO: (even beinga name rebind and not a real update) book = 'Fooled by Randomness' book = "$book - Nassim Taleb" book = "$book (2001)" assert 'Fooled by Randomness - Nassim Taleb (2001)' == book YES: book = 'Fooled by Randomness' bookWithAuthor = "$book - Nassim Taleb" completeBook = "$bookWithAuthor (2001)" assert 'Fooled by Randomness - Nassim Taleb (2001)' == completeBook
19.
Immutability NO: years = [2001,2002] years << 2003 years += [2004, 2005] assert [2001, 2002, 2003, 2004, 2005] == years YES: years = [2001, 2002] allYears = years + 2003 + [2004, 2005] assert [2001, 2002, 2003, 2004, 2005] == allYears
20.
Immutability def list =['Gr', 'vy'] NO: list.addAll 1, 'oo' assert list == ['Gr', 'oo', 'vy'] YES: assert list.plus(1, 'oo') == ['Gr', 'oo', 'vy'] assert list == ['Gr', 'vy']
21.
Immutability def list =[1, 2, 2, 3] NO: list.removeAll 2 assert list == [1, 3] YES: assert list.minus(2) == [1, 3] assert list == [1, 2, 2, 3]
Immutability Class @Immutable classCoordinates { Double latitude, longitude } def c1 = new Coordinates(latitude: 48.824068, longitude: 2.531733) def c2 = new Coordinates(48.824068, 2.531733) assert c1 == c2
27.
Higher-Order Functions First-Class Citizen Can be stored in variables Can be passed as function parameter Can be returned from functions Higher-Order Functions (First-Class Functions) Functions that take other functions as arguments or return them as results
28.
Closures def closure ={ 'Hello world!' } assert closure() == 'Hello world!' def sum = { a, b -> a + b } assert sum(2,3) == 5 def square = { it * it } assert square(9) == 81 final BASE = 1000 def salary = { variable -> BASE + variable } assert salary(500) == 1500
29.
Turn Methods intoClosures def salary(variable) { final BASE = 1000 BASE + variable } assert salary(500) == 1500 def salaryClosure = this.&salary assert salaryClosure(500) == 1500
Currying given: ƒ: (X x Y) -> Z then: 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
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]
40.
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]
41.
inject() NO: def total =0 [1, 2, 3].each { total += it } assert total == 6 YES: def total = [1, 2, 3].inject(0) { acc, n -> acc + n } assert total == 6
42.
find() NO: def result try { [1, 2, 3].each { if (it > 1) { result = it throw new Exception() // monstrous } } } catch(exception) { } assert result == 2 YES: assert [1, 2, 3].find{ it > 1 } == 2
43.
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 << person3 assert family.max{ it.age }.age == 61 assert family.collect{ it.age }.max() == 61 assert family*.age.max() == 61
44.
Refactoring def exists =false family.each { person -> if (person.age > 60) { exists = true } } assert exists == true def exists = family.inject(false) { found, person -> if (person.age > 60) { found = true } return found } assert exists == true assert family.any{ it.age > 60 } == true
45.
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 << rafa assert osokers.unique(false) .findAll{ it.age > 30} .sort{ it.lastname } == [marcin, rafa] assert osokers == [rafa, marcin, arturo, rafa]
46.
Combinator Functions // Proceduralstyle def count = 0 for (i in (1 .. 1000)) { if (i % 2) { count += ("$i".size()) } } assert count == 1445 // Functional style def count = (1 .. 1000).findAll{ it % 2 } .collect{ "$it" } .inject(0) { sum, num -> sum + num.size() } assert count == 1445
47.
Lazy Evaluation Only doesas much work as necessary Delays the evaluation of the expression until it's needed CPU efficient The value is not calculated or assigned until the value is requested Manage potentially infinite data structures Only a manageable subset of the data will actually be used
48.
Lazy Evaluation class Person{ @Lazy String name = 'Arturo' } def person = new Person() assert !(person.dump().contains('Arturo')) assert person.name.size() == 6 assert person.dump().contains('Arturo')
Tail Call Optimization 3techniques: The compiler transform the recursion into a loop λ Let the JVM recognize the recursion and eliminate it λ Transform the recursion into iterative by hand λ
58.
Tail Call Optimization 3techniques: 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?
59.
Tail Call Optimization deffactorial factorial = { n -> n == 1 ? 1 : n * factorial(n - 1) } factorial(1000)
60.
Tail Call Optimization rflow kO ve def factorial S tac factorial = { n -> n == 1 ? 1 : n * factorial(n - 1) } factorial(1000)
61.
Tail Call Optimization deffactorial factorial = { n, BigInteger acc = 1 -> n == 1 ? acc : factorial(n - 1, n * acc) } factorial(1000)
62.
Tail Call Optimization rflow kO ve def factorial S tac factorial = { n, BigInteger acc = 1 -> n == 1 ? acc : factorial(n - 1, n * acc) } factorial(1000)
63.
Tail Call Optimization deffactorial factorial = { n, BigInteger acc = 1 -> n == 1 ? acc : factorial.trampoline(n - 1, n * acc) }.trampoline() factorial(1000)
64.
Trampolining def even, odd even= { x -> x == 0 ? true : odd.trampoline(x - 1) }.trampoline() odd = { x -> x == 0 ? false : even.trampoline(x - 1) }.trampoline() assert even(1000) == true