discovering functional treasure in idiomatic groovy

42
Discovering Functional Treasure in Idiomatic Groovy Naresha K Enteleki Solutions [email protected] @naresha_k

Upload: naresha-k

Post on 25-Dec-2014

196 views

Category:

Technology


1 download

DESCRIPTION

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

TRANSCRIPT

Page 1: Discovering functional treasure in idiomatic Groovy

Discovering Functional Treasure in

Idiomatic Groovy

Naresha K Enteleki Solutions

[email protected]

@naresha_k

Page 2: Discovering functional treasure in idiomatic Groovy
Page 3: Discovering functional treasure in idiomatic Groovy

An imperative

language on JVM

A dynamic

with Functional Flavour

Page 4: Discovering functional treasure in idiomatic Groovy

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

Page 5: Discovering functional treasure in idiomatic Groovy

Prerequisites

Page 6: Discovering functional treasure in idiomatic Groovy

Function

!def sayHello(){!! println 'Hello'!}!!sayHello()!

Page 7: Discovering functional treasure in idiomatic Groovy
Page 8: Discovering functional treasure in idiomatic Groovy

Closuredef wish = {!! println "Hello"!}!!wish()

def wishFriend = {!! println "Hello $it"!} !!wishFriend 'Raj'

def wishFriend = { to ->!! println "Hello $to"!}!!wishFriend 'Raj'

Page 9: Discovering functional treasure in idiomatic Groovy

Closure - No Arg

def wish = { ->!! println "Hello"!}!!wish()

Page 10: Discovering functional treasure in idiomatic Groovy

Closure - Multiple args

def wishWithMessage = { to, message ->!! println "Hello $to, $message"!}!!wishWithMessage "Raj", "Good Evening"

Page 11: Discovering functional treasure in idiomatic Groovy

Closures = Power functions

def wishWithMessage = { to, message ->!! println "Hello $to, $message"!}!!wishWithMessage "Raj", "Good Evening"

def <var> = <closure>

Functions as Values

Page 12: Discovering functional treasure in idiomatic Groovy

Sample Dataimport 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'])!

Page 13: Discovering functional treasure in idiomatic Groovy

Geeks who can speak Groovy

def findGroovyGeeksImperative(geeks){!! def groovyGeeks = []!! for(geek in geeks){!! if(geek.languages.contains('Groovy')){!! groovyGeeks << geek!! }!! }!! groovyGeeks!}

Page 14: Discovering functional treasure in idiomatic Groovy

Geeks who can speak Groovy

def findGroovyGeeksImperative(geeks){!! def groovyGeeks = []!! for(geek in geeks){!

! if(geek.languages.contains('Groovy')){!

! groovyGeeks << geek!! }!! }!! groovyGeeks!}

Page 15: Discovering functional treasure in idiomatic Groovy

Generalised

def findGeeks(geeks, String language){!! def knowsLang = []!! for(geek in geeks){!! if(geek.languages.contains(language)){!! knowsLang << geek!! }!! }!! knowsLang!}!

Page 16: Discovering functional treasure in idiomatic Groovy

Towards Idiomatic Groovydef 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')}!}

Page 17: Discovering functional treasure in idiomatic Groovy

Reusable

def knowsGroovy = { geek -> !! geek.languages.contains('Groovy')!}!!def findGeeksFunctional(geeks, criterion){!! geeks.findAll(criterion)!}!!println findGeeksFunctional(geeks, knowsGroovy)

Higher Order Functions

Page 18: Discovering functional treasure in idiomatic Groovy

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)

Page 19: Discovering functional treasure in idiomatic Groovy

Command Pattern

def sayHello = {!! println "Hello"!}!!def sayHi = {!! println "Hi"!}!![sayHello, sayHi].each{ command ->!! command()!}

Page 20: Discovering functional treasure in idiomatic Groovy

Execute Arounddef sayHello = {!! println "Hello"!}!!def sayHi = {!! println "Hi"!}!![sayHello, sayHi].each{ command ->!! println "Before Command"!! command()!! println "After Command"!}

Page 21: Discovering functional treasure in idiomatic Groovy

Code Smell!

def knowsGroovy = { geek -> !! geek.languages.contains('Groovy')!}!!def knowsClojure = { geek ->!! geek.languages.contains('Clojure')!}

Page 22: Discovering functional treasure in idiomatic Groovy

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')

Page 23: Discovering functional treasure in idiomatic Groovy

A Better Approachdef 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

Page 24: Discovering functional treasure in idiomatic Groovy

Geeks

• Knows Groovy

• At least 25 years old

Page 25: Discovering functional treasure in idiomatic Groovy

Composing emdef 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

Page 26: Discovering functional treasure in idiomatic Groovy

Towards Immutable Datadef 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()

Page 27: Discovering functional treasure in idiomatic Groovy

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

Page 28: Discovering functional treasure in idiomatic Groovy

Demo

Page 29: Discovering functional treasure in idiomatic Groovy

import groovy.transform.*!!@TailRecursive!def factorial(number, fact = 1){!! number == 0 ? fact : factorial(number - 1, fact * number)!}!!println factorial(2500G)

Tail Call Optimization

Page 30: Discovering functional treasure in idiomatic Groovy

Prior to Groovy 2.3

def fact!fact = { number, result ->!! number == 0 ? result : !! ! fact.trampoline(number-1, result * number)!}.trampoline()

Page 31: Discovering functional treasure in idiomatic Groovy

Slow Functions

Page 32: Discovering functional treasure in idiomatic Groovy

import groovy.transform.*!!@Memoized!def timeConsumingOperation(int number){!! println "Performing computation"!! number * number!}!!println timeConsumingOperation(2)!println timeConsumingOperation(2)

Memoization

Page 33: Discovering functional treasure in idiomatic Groovy

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()}

Page 34: Discovering functional treasure in idiomatic Groovy

Defer

Page 35: Discovering functional treasure in idiomatic Groovy

Deferimport 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

Page 36: Discovering functional treasure in idiomatic Groovy

Recursion vs Iteration

Page 37: Discovering functional treasure in idiomatic Groovy

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))

Page 38: Discovering functional treasure in idiomatic Groovy

Recursion vs Iteration

println ages.inject(0) { s, item ->!! s + item!}

Page 39: Discovering functional treasure in idiomatic Groovy

The Ultimate Lesson

https://twitter.com/mfeathers/status/29581296216

Page 40: Discovering functional treasure in idiomatic Groovy

Functional Treasures Functions as values (First class citizens)

Higher order functions

Curried Functions

Function Composition

Pure Functions (Immutability)

Tail Call Optimization

Memoization

Lazy Evaluation

Page 41: Discovering functional treasure in idiomatic Groovy

Welcome to

Page 42: Discovering functional treasure in idiomatic Groovy

References

• https://github.com/naresha/functionalconf2014