An Introduction to core ideas, characteristics and benefits of functional programming and their implementation within the so called ‘object – functional’ language Scala.
Leaving the widely known concepts of object oriented programming aside, the focus is directed on how to leverage Scala in order to perform the following topics (extract):
* Functions and Function types
* Lambdas and Closures
* Currying and partial Argument Application
* Algebraic datatypes and Pattern matching
* Higher Order Functions
* Composition and Combinators
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Functional Scala I
1. Functional Scaλa
Functional Programming with Scala
25.08.2010
Java User Group Frankfurt / Main
Mario Gleichmann
Mario Gleichmann JUG Frankfurt / Main
2. Introduction
Mario Gleichmann
site: www.mg-informatik.de
blog: 'brain driven development'
gleichmann.wordpress.com
mail: mario.gleichmann@mg-informatik.de
Mario Gleichmann 2 JUG Frankfurt / Main
3. What is Functional Programming ?
Imperative Style
int sum = 0;
for( int i=1; i<=10; i++ ){
sum = sum + i;
}
Mario Gleichmann 3 JUG Frankfurt / Main
4. What is Functional Programming ?
Imperative Style
int sum = 0;
for( int i=1; i<=10; i++ ){
sum = sum + i;
}
Instruction based
Computation method is variable assignment
Mario Gleichmann 4 JUG Frankfurt / Main
5. What is Functional Programming ?
Functional Style
val sum = fold( 1 to 10, _+_ )
Mario Gleichmann 5 JUG Frankfurt / Main
6. What is Functional Programming ?
Functional Style
val sum = fold( 1 to 10, add )
Mario Gleichmann 6 JUG Frankfurt / Main
7. What is Functional Programming ?
Functional Style
val sum = fold( 1 to 10, add )
Expression based
Computation method is function application
Mario Gleichmann 7 fcn JUG Frankfurt / Main
8. What makes a Function ?
Function Literals
( x :Int, y :Int ) => x + y
Mario Gleichmann 8 Fcn val JUG Frankfurt / Main
9. What makes a Function ?
Function Values
val add = ( x :Int, y :Int ) => x + y
Mario Gleichmann 9 Elm JUG Frankfurt / Main
10. What makes a Function ?
Elements
val add = ( x :Int, y :Int ) => x + y
Function name Argument list Function expression
Mario Gleichmann 10 Tp JUG Frankfurt / Main
11. What makes a Function ?
Function Types
val add = ( x :Int, y :Int ) => x + y
Type of add : ( Int , Int ) => Int
Mario Gleichmann 11 Obj JUG Frankfurt / Main
12. What makes a Function ?
Note : In Scala, everything is an Object
val add = ( x :Int, y :Int ) => x + y
val add = new Function2[ Int, Int, Int ] {
def apply( x :Int, y: Int ) : Int = x + y
}
Mario Gleichmann 12 xplct Tp dcl JUG Frankfurt / Main
13. What makes a Function ?
Function Types
val add : ( Int, Int ) => Int = ( x :Int, y :Int ) => x + y
Explicit Type Declaration
Mario Gleichmann 13 Shrt JUG Frankfurt / Main
14. What makes a Function ?
Argument Shortcuts
Argument List omitted !
val add : ( Int, Int ) => Int = _+_
First Parameter Second Parameter
Mario Gleichmann 14 app JUG Frankfurt / Main
15. What makes a Function ?
Function Application
val add : ( Int, Int ) => Int = _+_
Function Application
...
add( 3, 8 ) >> 11
Mario Gleichmann 15 App obj JUG Frankfurt / Main
16. What makes a Function ?
Function Application
val add : ( Int, Int ) => Int = _+_
...
add( 3, 8 ) >> 11
add.apply( 3, 8 ) >> 11
Mario Gleichmann 16 Mthd JUG Frankfurt / Main
17. What makes a Function ?
Methods
object Math{
...
def mult( x :Int, y :Int ) : Int = x * y
...
}
Mario Gleichmann 17 Elm JUG Frankfurt / Main
18. What makes a Function ?
Elements
object Math{
Result Type
def mult( x :Int, y :Int ) : Int = x * y
}
Method name Argument list Method body
Mario Gleichmann 18 Tpe JUG Frankfurt / Main
19. What makes a Function ?
Method Types
def mult( x :Int, y :Int ) : Int = x * y
Type of mult : ( Int , Int ) Int
Mario Gleichmann 19 clsrs JUG Frankfurt / Main
20. Closures
var limit = 18
val isAdult = ( age :Int ) => age >= limit
Type of isAdult : Int => Boolean
Mario Gleichmann 20 Bnd var JUG Frankfurt / Main
21. Closures
var limit = 18
val isAdult = ( age :Int ) => age >= limit
Bound variable
Mario Gleichmann 21 Fre var JUG Frankfurt / Main
22. Closures
var limit = 18 Free variable
val isAdult = ( age :Int ) => age >= limit
Mario Gleichmann 22 Opn Trm JUG Frankfurt / Main
23. Closures
Open Terms
var limit = 18 Free variable
val isAdult = ( age :Int ) => age >= limit
'Open term'
Mario Gleichmann 23 Cls ovr JUG Frankfurt / Main
24. Closures
'Closing over'
var limit = 18
val isAdult = ( age :Int ) => age >= limit
Mario Gleichmann 24 Clsd trm JUG Frankfurt / Main
25. Closures
var limit = 18
val isAdult = ( age :Int ) => age >= limit
'Closed term'
Mario Gleichmann 25 appl JUG Frankfurt / Main
26. Closures
var limit = 18
val isAdult = ( age :Int ) => age >= limit
val isGermanAdult = isAdult( 20 ) >> true
Mario Gleichmann 26 Lim chng JUG Frankfurt / Main
27. Closures
var limit = 18
val isAdult = ( age :Int ) => age >= limit
val isGermanAdult = isAdult( 20 ) >> true
limit = 21
val isUnitesStatesAdult = isAdult( 20 )
Mario Gleichmann 27 Dym bnd JUG Frankfurt / Main
28. Closures
var limit = 18
val isAdult = ( age :Int ) => age >= limit
val isGermanAdult = isAdult( 20 ) >> true
'Dynamic' bound
limit = 21
val isUnitesStatesAdult = isAdult( 20 ) >> false
Mario Gleichmann 28 Dta Tp JUG Frankfurt / Main
29. Data types
data Natural = Zero | Succ( Natural )
'Constructors'
Mario Gleichmann 29 smp JUG Frankfurt / Main
30. Data types
data Natural = Zero | Succ( Natural )
val zero = Zero
val one = Succ( Zero )
val four = Succ( Succ ( Succ ( Succ ( Zero ) ) ) )
Mario Gleichmann 30 Int JUG Frankfurt / Main
31. Data types
data Integer = … , -3, -2, -1, 0, 1, 2, 3, ...
val zero = 0
val one = 1
val four = 4
Mario Gleichmann 31 Fib pttn JUG Frankfurt / Main
32. Operating on data types
Pattern Matching
fibonacci( 0 ) → 0
fibonacci( 1 ) → 1
fibonacci( n ) → fibonacci( n – 1 ) + fibonacci( n – 2 )
Mario Gleichmann 32 Ptt mtc JUG Frankfurt / Main
33. Operating on data types
Pattern Matching
val fib : Int => Int = ( i :Int ) => i match {
case 0 => 0
case 1 => 1
case n => fib( n - 1 ) + fib( n - 2 )
}
Mario Gleichmann 33 othw JUG Frankfurt / Main
34. Operating on data types
Pattern Matching
val fib : Int => Int = ( i :Int ) => i match {
case 0 => 0
case 1 => 1
case _ => fib( i - 1 ) + fib( i - 2 )
}
'otherwise'
Mario Gleichmann 34 Lst JUG Frankfurt / Main
35. Algebraic Datatypes
data List a = Nil | Cons a ( List a )
Mario Gleichmann 35 Cnstr JUG Frankfurt / Main
36. Algebraic Datatypes
Value Constructors
data List[T] = Nil | T :: List[T]
'Constructors'
Mario Gleichmann 36 smp JUG Frankfurt / Main
37. Algebraic Datatypes
Value Construction
data List[T] = Nil | T :: List[T]
val emptyList = Nil
Mario Gleichmann 37 smp JUG Frankfurt / Main
38. Algebraic Datatypes
Value Construction
data List[T] = Nil | T :: List[T]
val emptyList = Nil
val anotherList = 5 :: 4 :: 3 :: 2 :: 1 :: Nil
Mario Gleichmann 38 Rght assoc JUG Frankfurt / Main
39. Algebraic Datatypes
Value Construction
data List[T] = Nil | T :: List[T]
val emptyList = Nil
val anotherList = 5 :: ( 4 :: ( 3 :: ( 2 :: (1 :: Nil ) ) ) )
Mario Gleichmann 39 Smp tl JUG Frankfurt / Main
40. Operating on algebraic data types
Pattern Matching
def tail [T] ( list :List[T] ) = list match {
case Nil => Nil
case x :: xs => xs
}
Type of tail: [T] ( List[T] ) List[T]
Mario Gleichmann 40 De con JUG Frankfurt / Main
41. Operating on algebraic data types
Pattern Matching
def tail [T] ( list :List[T] ) = list match {
case Nil => Nil
case x :: xs => xs
}
'De-Construction'
Mario Gleichmann 41 Dnt cr JUG Frankfurt / Main
42. Operating on algebraic data types
Pattern Matching
val length : List[ _ ] => Int = _ match {
case Nil => 0
case _ :: xs => 1 + length( xs )
}
'some head' (don't care)
Type of length: ( List[ _ ] ) => Int
Mario Gleichmann 42 Grd JUG Frankfurt / Main
43. Operating on algebraic data types
Pattern Matching
def insert[ T <% Ordered[ T ] ] ( elem :T, list :List[T] ) : List[T] =
list match {
case Nil => elem :: Nil
case x :: xs if elem <= x => elem :: x :: xs
case x :: xs => x :: insert( elem, xs )
}
Guard
Mario Gleichmann 43 Smp Tr JUG Frankfurt / Main
44. Algebraic Datatypes
Example - Tree
data Tree = Empty | Leaf Int | Node Int Tree Tree
Mario Gleichmann 44 Cs clss JUG Frankfurt / Main
45. Algebraic Datatypes
Example - Tree
data Tree = Empty | Leaf Int | Node Int Tree Tree
abstract case class Tree()
case object Empty extends Tree
case class Leaf( value: Int ) extends Tree
case class Node( value: Int, left :Tree, right: Tree ) extends Tree
Mario Gleichmann 45 insrt JUG Frankfurt / Main
46. Algebraic Datatypes
Buildin' an unbalanced, ordered Tree
val insert :( Int, Tree ) => Tree = ( elem :Int, tree :Tree ) => tree match {
case Empty => Leaf( elem )
case Node( x, left, right ) if elem < x => Node( x, insert( elem, left ), right )
case Node( x, left, right ) if elem >= x => Node( x, left, insert( elem, right ) )
case Leaf( x ) if elem < x => Node( x, Leaf( elem ), Empty )
case leaf @ Leaf( x ) if elem >= x => Node( elem, leaf, Empty )
}
Mario Gleichmann 46 dpth JUG Frankfurt / Main
47. Algebraic Datatypes
Pattern Matching
val depth :Tree => Int = _ match {
case Empty => 0
case Leaf( _ ) => 1
case Node( _, left, right ) => 1 + max( depth( left ), depth( right ) )
}
Mario Gleichmann 47 Prt isb JUG Frankfurt / Main
48. Partial Functions
case class Isbn( groupNr :Int, publisherNr :Int, titleNr :Int )
val publisherRegionDE = ( isbn :Isbn ) => isbn match {
case Isbn( 3, pubNr, _ ) => "D" + ( pubNr.toString charAt 0 )
}
…
publisherRegionDE( Isbn( 3, 677873, 8823 ) ) ) >> “D6“
Mario Gleichmann 48 unmtch JUG Frankfurt / Main
49. Partial Functions
case class Isbn( groupNr :Int, publisherNr :Int, titleNr :Int )
val publisherRegionDE = ( isbn :Isbn ) => isbn match {
case Isbn( 3, pubNr, _ ) => "D" + ( pubNr.toString charAt 0 )
}
?
…
publisherRegionDE( Isbn( 0, 677873, 8823 ) ) ) >>
Mario Gleichmann 49 Mtch err JUG Frankfurt / Main
50. Partial Functions
case class Isbn( groupNr :Int, publisherNr :Int, titleNr :Int )
val publisherRegionDE = ( isbn :Isbn ) => isbn match {
case Isbn( 3, pubNr, _ ) => "D" + ( pubNr.toString charAt 0 )
}
…
publisherRegionDE( Isbn( 0, 677873, 8823 ) ) ) >> MatchError
Mario Gleichmann 50 Prt fnc JUG Frankfurt / Main
51. Partial Functions
type =>?[-A, +B] = PartialFunction[A, B]
val publisherRegionDE : Isbn =>? String = {
case Isbn( 3, pubNr, _ ) => "D" + ( pubNr.toString charAt 0 )
}
…
publisherRegionDE.isDefinedAt( Isbn( 0, 677873, 8823 ) ) ) >> false
Mario Gleichmann 51 chn JUG Frankfurt / Main
52. Partial Functions
Partial Function Chaining
val publisherRegionUS : Isbn =>? String = {
case Isbn( 0, pubNr, _ ) => …
case Isbn( 1, pubNr, _ ) => ...
}
...
val allKnownPubs = publisherRegionDE orElse publisherRegionUS
...
allKnownPubs( Isbn( 0, 677873, 8823 ) ) >> “WY“
Mario Gleichmann 52 cmprn JUG Frankfurt / Main
53. Comprehensions
Set Comprehensions (Mathematics)
{ x2 | x ∈ { 1 .. 5 } }
>> Set : { 1, 4, 9, 16, 25 }
Mario Gleichmann 53 Smp scla JUG Frankfurt / Main
54. Comprehensions
val pow :(Int,Int) => Int = ( base :Int, exp :Int ) =>
if( exp == 0 ) 1 else base * pow( base, exp - 1 )
Range ...
…
val squares = for( x <- ( 1 to 5 ) ) yield pow( x, 2 )
Mario Gleichmann 54 grn JUG Frankfurt / Main
55. Comprehensions
val pow :(Int,Int) => Int = ( base :Int, exp :Int ) =>
if( exp == 0 ) 1 else base * pow( base, exp - 1 )
… as Generator
…
val squares = for( x <- ( 1 to 5 ) ) yield pow( x, 2 )
>> Seq( 1, 4, 9, 16, 25 )
Mario Gleichmann 55 Mltp gen JUG Frankfurt / Main
56. Comprehensions
Multiple Generators
Tuple2
val pairs = for( x <- (1 to 3 ); y <- ( 1 to x ) ) yield (y,x)
>> Seq( (1,1), (1,2), (2,2), (1,3), (2,3), (3,3) )
Mario Gleichmann 56 Smp fltn JUG Frankfurt / Main
57. Comprehensions
Example – Flatten a List of Lists
val flatten = ( xss :List[ List[Int] ] ) =>
for( xs <- xss; x <- xs ) yield x
...
flatten( List( List(1,2), List( 5,6,8 ), List( 21,23,24 ) ) )
>> List(1, 2, 5, 6, 8, 21, 23, 24)
Mario Gleichmann 57 Smp int fact JUG Frankfurt / Main
58. Comprehensions
Example – All factors of an Integer
val factors = ( n :Int ) => for( x <- ( 1 to n ) if n % x == 0 ) yield x
... Guard
factors( 15 )
>> Seq( 1, 3, 5, 15 )
Mario Gleichmann 58 def prm JUG Frankfurt / Main
59. Comprehensions
Example – Test 'prime' on Integer
val factors = ( n :Int ) => for( x <- ( 1 to n ) if n % x == 0 ) yield x
...
val prime = ( n :Int ) => factors( n ).toList == List( 1, n )
Mario Gleichmann 59 def prms JUG Frankfurt / Main
60. Comprehensions
Example – All primes up to an Integer
val factors = ( n :Int ) => for( x <- ( 1 to n ) if n % x == 0 ) yield x
...
val prime = ( n :Int ) => factors( n ).toList == List( 1, n )
…
val primes = (n :Int) => for( x <- (1 to n) if prime( x ) ) yield x
Mario Gleichmann 60 Hgh rdr Fcn JUG Frankfurt / Main
61. Higher Order Functions
val filterEvenValues = ( xs :List[Int] ) => {
for( x <- xs; if x % 2 == 0 ) yield x
}
Mario Gleichmann 61 Lcl fcn JUG Frankfurt / Main
62. Higher Order Functions
Local Functions
val filterEvenValues = ( xs :List[Int] ) => {
Local
val isEven = ( i :Int ) => i % 2 == 0 Function
Definition
for( x <- xs; if isEven( x ) ) yield x
}
Mario Gleichmann 62 Smp od JUG Frankfurt / Main
63. Higher Order Functions
val filterOddValues = ( xs :List[Int] ) => {
val isOdd = ( i :Int ) => i % 2 == 1
for( x <- xs; if isOdd( x ) ) yield x
}
Mario Gleichmann 63 rfctg JUG Frankfurt / Main
64. Higher Order Functions
Refactoring ...
val filterOddValues = ( xs :List[Int] ) => {
val isOdd : Int => Boolean = _ % 2 == 1
for( x <- xs; if isOdd( x ) ) yield x
}
Mario Gleichmann 64 bstrcn JUG Frankfurt / Main
65. Higher Order Functions
… via Abstraction
val filter = ( predicate: Int => Boolean , xs :List[Int] ) => {
for( x <- xs; if predicate( x ) ) yield x
}
Mario Gleichmann 65 Fcn Tp JUG Frankfurt / Main
66. Higher Order Functions
Functions as values
Accepting a Function as Argument
val filter = ( predicate: Int => Boolean , xs :List[Int] ) => {
for( x <- xs; if predicate( x ) ) yield x
}
Type of filter: ( Int => Boolean, List[Int] ) => List[Int]
Mario Gleichmann 66 smp JUG Frankfurt / Main
67. Higher Order Functions
Examples
val even : Int => Boolean = _ % 2 == 0
val odd : Int => Boolean = _ % 2 == 1
val prime : Int => Boolean = …
...
val candidates = List( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 )
val evenValues = filter( even, candidates )
val oddValues = filter( odd, candidates )
val primes = filter( prime, candidates )
Mario Gleichmann 67 Mthd crcn JUG Frankfurt / Main
68. Higher Order Functions
Coercion
def isPositive( x : Int ) : Boolean = x > 0
val candidates = List( -3, -2, -1, 0, 1, 2, 3 )
val positiveValues = filter( isPositive, candidates )
Mario Gleichmann 68 vs JUG Frankfurt / Main
69. Higher Order Functions
Coercion
def isPositive( x : Int ) : Boolean = x > 0
?
val candidates = List( -3, -2, -1, 0, 1, 2, 3 )
val positiveValues = filter( isPositive, candidates )
( Int ) : Boolean vs. ( Int ) => Boolean
Mario Gleichmann 69 mplct crcn JUG Frankfurt / Main
70. Higher Order Functions
Coercion
def isPositive( x : Int ) : Boolean = x > 0
!
val candidates = List( -3, -2, -1, 0, 1, 2, 3 )
val positiveValues = filter( isPositive, candidates )
Implicit Coercion to ( Int ) => Boolean
Mario Gleichmann 70 xplct crcn JUG Frankfurt / Main
71. Higher Order Functions
Coercion
Explicit Coercion to ( Int ) => Boolean
val isPositiveFunc : Int => Boolean = isPositive
val candidates = List( -3, -2, -1, 0, 1, 2, 3 )
val positiveValues = filter( isPositiveFunc, candidates )
Mario Gleichmann 71 lmbd xpr JUG Frankfurt / Main
72. Anonymous Functions
val isNegative = ( x :Int ) => x < 0
filter( isNegative, candidates )
Mario Gleichmann 72 nsrt JUG Frankfurt / Main
73. Anonymous Functions
val isNegative = ( x :Int ) => x < 0
filter( ( x :Int ) => x < 0, candidates )
'Lambda' Expression
Mario Gleichmann 73 TP infr JUG Frankfurt / Main
74. Anonymous Functions
Shortcuts
val isNegative = ( x :Int ) => x < 0
filter( x => x < 0, candidates )
Type of Argument inferred
Type of filter: ( Int => Boolean, List[Int] ) => List[Int]
Mario Gleichmann 74 shrtct JUG Frankfurt / Main
75. Anonymous Functions
Shortcuts
val isNegative = ( x :Int ) => x < 0
filter( _ < 0, candidates )
First Argument
Mario Gleichmann 75 Smp rsc ctrl JUG Frankfurt / Main
76. Example 1 - Resource Control
Reader reader = new BufferedReader( ... );
try{
System.out.println( reader.readLine() );
}
finally{
reader.close();
}
Mario Gleichmann 76 Mrk rc cnt JUG Frankfurt / Main
77. Example 1 - Resource Control
Reader reader = new BufferedReader( ... );
try{
System.out.println( reader.readLine() );
}
finally{
reader.close(); Resource Control !
}
Mario Gleichmann 77 Ln pttn JUG Frankfurt / Main
78. Example 1 - Resource Control
Loan Pattern
using ( new BufferedReader( ... ) ,
reader => println( reader.readLine() );
)
Mario Gleichmann 78 fst arg JUG Frankfurt / Main
79. Example 1 - Resource Control
Loan Pattern
1st Argument: Resource under control
using ( new BufferedReader( ... ) ,
reader => println( reader.readLine() );
)
Mario Gleichmann 79 scnd arg JUG Frankfurt / Main
80. Example 1 - Resource Control
Loan Pattern
using ( new BufferedReader( ... ) ,
reader => println( reader.readLine() );
)
2nd Argument: Anonymous Function, using Resource
Mario Gleichmann 80 def fcn JUG Frankfurt / Main
81. Example 1 - Resource Control
Loan Pattern
val using = ( reader: Reader , block: Reader => Unit ) => {
try{
block( reader )
}
finally{
reader.close
}
}
Mario Gleichmann 81 Smp lggn JUG Frankfurt / Main
82. Example 2 - Logging
val log = ( logger :Logger, level :LogLevel ) => {
val canLog = logger.canLog( level )
( msg :String ) => if( canLog ) logger.log( level, msg )
}
Type of log: ( Logger, LogLevel ) => ( String => Unit )
Returning a Function
Mario Gleichmann 82 Fcn appl JUG Frankfurt / Main
83. Example 2 - Logging
val log = ( logger :Logger, level :LogLevel ) => {
val canLog = logger.canLog( level )
( msg :String ) => if( canLog ) logger.log( level, msg )
}
…
val info = log( myErrorLogger , INFO )
val fatal = log( myErrorLogger , FATAL )
...
info( “...“ ) Expensive operation 'for nothing'
...
fatal( “failure occured ...“ + “...“ + ... )
Mario Gleichmann 83 cndn evln JUG Frankfurt / Main
84. Example 2 - Logging
val log = ( logger :Logger, level :LogLevel ) => {
val canLog = logger.canLog( level )
( x: () => String ) => if( canLog ) logger.log( level, x() )
}
Accepting a Function ... … conditional evaluation
Type of log: ( Logger, LogLevel ) => ( () => String ) => Unit
Mario Gleichmann 84 appl JUG Frankfurt / Main
85. Example 2 - Logging
val log = ( logger :Logger, level :LogLevel ) => {
val canLog = logger.canLog( level )
( x: () => String ) => if( isLog ) logger.log( level, x() )
}
…
val fatal = log( myErrorLogger , FATAL )
...
won't be evaluated at all
...
fatal( () => “failure occured ...“ + “...“ + ... )
Mario Gleichmann 85 blplt JUG Frankfurt / Main
86. Example 2 - Logging
val log = ( logger :Logger, level :LogLevel ) => {
val canLog = logger.canLog( level )
( x: () => String ) => if( isLog ) logger.log( level, x() )
}
…
val fatal = log( myErrorLogger , FATAL )
...
Annoying boilerplate
...
fatal( () => “failure occured ...“ + “...“ + ... )
Mario Gleichmann 86 cll b nme JUG Frankfurt / Main
87. Example 2 - Logging
val log = ( logger :Logger, level :LogLevel ) => {
val canLog = logger.isLog( level )
def logMsg(x : => String) = if( canLog ) logger.log( level, x )
logMsg _
} By-Name Parameter
Mario Gleichmann 87 appl JUG Frankfurt / Main
88. Example 2 - Logging
val log = ( logger :Logger, level :LogLevel ) => {
val isLog = logger.canLog( level )
def logMsg(x : => String) = if( canLog ) logger.log( level, x )
logMsg _
}
…
val fatal = log( myErrorLogger , FATAL )
...
fatal( “failure occured ...“ + “...“ + ... )
Mario Gleichmann 88 Smp cstm cntl JUG Frankfurt / Main
89. Example 3 – Custom Control Structures
def loop( body: => Unit ) : LoopUnlessCond =
new LoopUnlessCond( body )
protected class LoopUnlessCond( body: => Unit ) {
def unless( cond: => Boolean ) {
body
if ( !cond ) unless( cond )
}
}
Mario Gleichmann 89 appl JUG Frankfurt / Main
90. Example 3 – Custom Control Structures
var i = 10
loop {
println( "i = " + i )
i-=1
} unless ( i == 0 )
Mario Gleichmann 90 obj instc JUG Frankfurt / Main
91. Example 3 – Custom Control Structures
var i = 10
loop {
Instance of LoopUnlessCond
println( "i = " + i )
i-=1
} unless ( i == 0 )
Mario Gleichmann 91 prt appl JUG Frankfurt / Main
92. Partial Application
val isPrime = (x :Int) => ( 2 to x/2 ).forall( x % _ != 0 )
Type of isPrime: Int => Boolean
Mario Gleichmann 92 def prms wthn JUG Frankfurt / Main
93. Partial Application
Delegation
val isPrime = (x :Int) => ( 2 to x/2 ).forall( x % _ != 0 )
val primesWithin = ( xs :List[Int] ) => filter( isPrime , xs )
Type of filter: ( Int => Boolean, List[Int] ) => List[Int]
Mario Gleichmann 93 fxd var JUG Frankfurt / Main
94. Partial Application
Delegation
val isPrime = (x :Int) => ( 2 to x/2 ).forall( x % _ != 0 )
val primesWithin = ( xs :List[Int] ) => filter( isPrime , xs )
fixed variable
Mario Gleichmann 94 appl nappl JUG Frankfurt / Main
95. Partial Application
New from Old ...
val isPrime = (x :Int) => ( 2 to x/2 ).forall( x % _ != 0 )
val primesWithin = filter( isPrime, _ :List[Int] )
applied unapplied
Mario Gleichmann 95 Fcn Tp JUG Frankfurt / Main
96. Partial Application
New from Old ...
val isPrime = (x :Int) => ( 2 to x/2 ).forall( x % _ != 0 )
val primesWithin = filter( isPrime, _ :List[Int] )
Type of primesWithin: List[Int] => List[Int]
Mario Gleichmann 96 Crrng JUG Frankfurt / Main
97. Currying
val filter = ( pred: Int => Boolean , xs :List[Int] ) => {
for( x <- xs; if pred( x ) ) yield x
}
Type of filter: ( Int => Boolean , List[Int] ) => List[Int]
Mario Gleichmann 97 Crrd fcn JUG Frankfurt / Main
98. Currying
'Higher Order Lambda Closures' ...
val filter = ( pred: Int => Boolean ) => ( xs :List[Int] ) => {
for( x <- xs; if pred( x ) ) yield x
}
Mario Gleichmann 98 Crrd fcn Tp JUG Frankfurt / Main
99. Currying
'Higher Order Lambda Closures' ...
val filter = ( pred: Int => Boolean ) => ( xs :List[Int] ) => {
for( x <- xs; if pred( x ) ) yield x
}
Type of filter: ( Int => Boolean ) => List[Int] => List[Int]
Mario Gleichmann 99 sngl arg JUG Frankfurt / Main
100. Currying
'Higher Order Lambda Closures' ...
val filter = ( pred: Int => Boolean ) => ( xs :List[Int] ) => {
for( x <- xs; if pred( x ) ) yield x
}
Type of filter: ( Int => Boolean ) => List[Int] => List[Int]
Curried Function
Curried Function
Mario Gleichmann 100 xpln JUG Frankfurt / Main
101. Currying
'Higher Order Lambda Closures' ...
val filter = ( pred: Int => Boolean ) => ( xs :List[Int] ) => {
for( x <- xs; if pred( x ) ) yield x
}
Type of filter: ( Int => Boolean ) => List[Int] => List[Int]
... accepting one ... resulting in another
A function
(Function) Arg function
Mario Gleichmann 101 lmbd xpr JUG Frankfurt / Main
102. Currying
'Higher Order Lambda Closures' ...
val filter = ( pred: Int => Boolean ) => ( xs :List[Int] ) => {
for( x <- xs; if pred( x ) ) yield x
}
Type of filter: ( Int => Boolean ) => List[Int] => List[Int]
... is defined as a Lambda expession
Mario Gleichmann 102 cls ovr JUG Frankfurt / Main
103. Currying
'Higher Order Lambda Closures' ...
val filter = ( pred: Int => Boolean ) => ( xs :List[Int] ) => {
for( x <- xs; if pred( x ) ) yield x
}
Type of filter: ( Int => Boolean ) => List[Int] => List[Int]
... closes over to Arguments (Scope)
of surrounding Function 'filter'
Mario Gleichmann 103 Smp prms wthn JUG Frankfurt / Main
104. Example 1 – Extract primes
val filter = ( pred: Int => Boolean ) => ( xs :List[Int] ) => {
for( x <- xs; if pred( x ) ) yield x
}
val primesWithin = filter( isPrime )
Mario Gleichmann 104 Fcn Tp JUG Frankfurt / Main
105. Example 1 – Extract primes
val filter = ( pred: Int => Boolean ) => ( xs :List[Int] ) => {
for( x <- xs; if pred( x ) ) yield x
}
val primesWithin = filter( isPrime )
Type of primesWithin: List[Int] => List[Int]
Mario Gleichmann 105 appl JUG Frankfurt / Main
106. Example 1 – Extract primes
val filter = ( pred: Int => Boolean ) => ( xs :List[Int] ) => {
for( x <- xs; if pred( x ) ) yield x
}
val primesWithin = filter( isPrime )
...
primesWithin( List( 3, 4, 5, 6, 7 ) ) >> List( 3, 5, 7 )
Mario Gleichmann 106 Smp rc mgmt JUG Frankfurt / Main
107. Example 2 – Ressource Management
val initQuery =
(dataSource :DataSource) => (query :String) => ( extractor :ResultSet => Unit ) => {
try{
val conn = dataSource.getConnection
val stmt = conn.createStatement
val resultSet = stmt.executeQuery( query )
extractor( resultSet )
}
finally{
try{
if( conn != null ) conn.close
}
finally{
if( stmt != null ) stmt.close
}
}
}
Mario Gleichmann 107 appl JUG Frankfurt / Main
108. Example 2 – Ressource Management
val dataSource :DataSource = ...;
...
val query = initQuery( dataSource )
…
query( "select * from User where age > 18" ) { result :ResultSet =>
while( result.next ) { .... }
}
…
query( "select * from Account where balance < 1000" ) { result :ResultSet =>
while( result.next ) { .... }
}
Mario Gleichmann 108 smmy JUG Frankfurt / Main
109. Summary
Scala supports a style of expression based, functional programming,
offering
● Functions and Closures as first class values
● Algebraic Datatypes and Pattern Matching
● Comprehensions
● Higher Order Functions and Lambda Expressions
● Currying
Mario Gleichmann 109 JUG Frankfurt / Main
111. References
Scala Home www.scala-lang.org
Dr. Erik Meijer C9 Lectures – Functional Programming Fundamentals
http://channel9.msdn.com
Graham Hutton Programming in Haskell
Cambridge
Odersky, Spoon, Venners Programming in Scala
artima
Mario Gleichmann 111 JUG Frankfurt / Main