Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Functional Scala II (in practice)
1. Functional Scaλa
… in Practice
20.10.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
4. What is Functional Programming ?
Functional Style
val sum = fold( 1 to 10, add )
Expression based
Computation method is function application
Mario Gleichmann 4 fcn JUG Frankfurt / Main
5. What makes a Function ?
Function Types
val add = ( x :Int, y :Int ) => x + y
Type of add : ( Int , Int ) => Int
Mario Gleichmann 5 Obj JUG Frankfurt / Main
6. Closures
'closing over'
var limit = 18
val isAdult = ( age :Int ) => age >= limit
'Closed term'
Mario Gleichmann 6 appl JUG Frankfurt / Main
7. 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 7 insrt JUG Frankfurt / Main
8. 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 8 Prt isb JUG Frankfurt / Main
9. 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 9 chn JUG Frankfurt / Main
10. Comprehensions
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 10 Hgh rdr Fcn JUG Frankfurt / Main
11. Higher Order Functions
val filter = ( predicate: Int => Boolean , xs :List[Int] ) => {
for( x <- xs; if predicate( x ) ) yield x
}
Mario Gleichmann 11 Fcn Tp JUG Frankfurt / Main
12. Lambda Expressions
filter( num => num % 2 == 0, List( 1, 2, 3, 4, 5, 6 ) )
…
filter( _ > 0, List( -1, 5, 0, -3, 7 ) )
Mario Gleichmann 12 fst arg JUG Frankfurt / Main
14. Partial Application
val isPrime = (x :Int) => ( 2 to x/2 ).forall( x % _ != 0 )
Type of isPrime: Int => Boolean
Mario Gleichmann 14 def prms wthn JUG Frankfurt / Main
15. 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 15 fxd var JUG Frankfurt / Main
16. 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 16 appl nappl JUG Frankfurt / Main
17. 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 17 Fcn Tp JUG Frankfurt / Main
18. 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 18 Crrng JUG Frankfurt / Main
20. 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 20 Crrd fcn JUG Frankfurt / Main
21. Currying
'Higher Order Lambda Closures' ...
val filter = ( pred: Int => Boolean ) => ( xs :List[Int] ) => {
for( x <- xs; if pred( x ) ) yield x
}
Mario Gleichmann 21 Crrd fcn Tp JUG Frankfurt / Main
22. 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 22 sngl arg JUG Frankfurt / Main
23. 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 23 sngl
xpln arg JUG Frankfurt / Main
24. 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 24 lmbd xpr JUG Frankfurt / Main
25. 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 25 cls ovr JUG Frankfurt / Main
26. 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 26 Smp prms wthn JUG Frankfurt / Main
27. 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 27 Fcn Tp JUG Frankfurt / Main
28. 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 28 appl JUG Frankfurt / Main
29. 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 29 Smp rc mgmt JUG Frankfurt / Main
30. 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 30 appl JUG Frankfurt / Main
31. 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 31 smmy JUG Frankfurt / Main
33. Combinators
val power : Int => Int => Int =
( base :Int ) => ( exp :Int ) =>
if( exp == 1 ) base else base * power( base )( exp - 1 )
...
val square = power( _ :Int )( 2 )
Mario Gleichmann 33 JUG Frankfurt / Main
34. Combinators
val power : Int => Int => Int =
( base :Int ) => ( exp :Int ) =>
if( exp == 1 ) base else base * power( base )( exp - 1 )
...
val square = power( _ :Int )( 2 )
Type of square : Int => Int
Mario Gleichmann 34 JUG Frankfurt / Main
35. Combinators
val power : Int => Int => Int =
( base :Int ) => ( exp :Int ) =>
if( exp == 1 ) base else base * power( base )( exp - 1 )
...
val square = power( _ :Int )( 2 )
Partial Application 'in the middle'
Mario Gleichmann 35 JUG Frankfurt / Main
36. Combinators
def flipArgs [A, B, C] ( f: A => B => C ) : B => A => C =
( x: B ) => ( y: A ) => f (y) (x)
Transforms to another Function,
expecting arguments in reversed order
Mario Gleichmann 36 JUG Frankfurt / Main
37. Combinators
def flipArgs [A, B, C] ( f: A => B => C ) : B => A => C =
( x: B ) => ( y: A ) => f (y) (x)
…
val square = flipArgs( power )( 2 )
… now just exploit Currying
Mario Gleichmann 37 JUG Frankfurt / Main
38. Combinators
Function Composition
f :: B => C
g :: A => B
x ∈ A
( f o g )( x ) = f ( g ( x ) )
( f o g ) :: A => C
Mario Gleichmann 38 JUG Frankfurt / Main
39. Combinators : Function Composition
def o [A,B,C] ( f: B => C ) ( g: A => B ) : A => C =
( x :A ) => f( g( x ) )
...
val mult = ( x :Int ) => ( y: Int ) => x * y
val add = ( x :Int ) => ( y: Int ) => x + y
...
val doubleSucc = o ( mult(2) ) ( add(1) )
Type of doubleSucc : Int => Int
Mario Gleichmann 39 JUG Frankfurt / Main
40. Combinators : Function Composition
def o [A,B,C] ( f: B => C ) ( g: A => B ) : A => C =
( x :A ) => f( g( x ) )
...
val mult = ( x :Int ) => ( y: Int ) => x * y
val add = ( x :Int ) => ( y: Int ) => x + y
...
val doubleSucc = o ( mult(2) ) ( add(1) )
doubleSucc( 7 )
>> 16
Mario Gleichmann 40 JUG Frankfurt / Main
41. Combinators : Function Composition
def o [A,B,C] ( f: B => C ) ( g: A => B ) : A => C =
( x :A ) => f( g( x ) )
...
val mult = ( x :Int ) => ( y: Int ) => x * y
val add = ( x :Int ) => ( y: Int ) => x + y
...
val doubleSucc = o ( mult(2) ) ( add(1) )
doubleSucc( 7 )
Postfix ...
>> 16
Mario Gleichmann 41 JUG Frankfurt / Main
42. Combinators : Function Composition
class RichFunc [B, C] ( f: B => C ) {
def o[A] ( g: A => B ) = (x :A) => f( g( x ) )
}
implicit def toRichFunc[B,C]( f: B => C ) = new RichFunc( f )
...
val doubleSucc = mult(2) o add(1)
doubleSucc( 7 ) Infix !!!
>> 16
Mario Gleichmann 42 JUG Frankfurt / Main
43. Combinators : Function Composition
class RichFunc [B, C] ( f: B => C ) {
def o[A] ( g: A => B ) = (x :A) => f( g( x ) )
}
implicit def toRichFunc[B,C]( f: B => C ) = new RichFunc( f )
...
val doubleSucc = mult(2) o add(1)
doubleSucc( 7 ) 'Point free style' of function definition
>> 16
Mario Gleichmann 43 JUG Frankfurt / Main
44. Example: Word Counter
Count all even words within a sentence:
“Hello World“ → 0
“The fox jumps over the lazy dog“ → 2
"This sentence contains five even words" → 5
Mario Gleichmann 44 JUG Frankfurt / Main
45. Example: Word Counter
Count all even words within a sentence:
“Hello World“ → 0
“The fox jumps over the lazy dog“ → 2
"This sentence contains five even words" → 5
Basic Functions:
parse Words → Word to length → filter even → count
Mario Gleichmann 45 JUG Frankfurt / Main
46. Example: Word Counter
Basic Functions
val words = ( sentence : String ) => sentence.split( " " ).toList
val length = ( ws :List[String] ) => for( w <- ws ) yield w.length
val filter = ( predicate: Int => Boolean ) => ( xs :List[Int] ) => ...
val even = ( i :Int ) => i % 2 == 0
val size = ( xs :List[ _ ] ) => xs.size
Mario Gleichmann 46 JUG Frankfurt / Main
47. Example: Word Counter
val words = ( sentence : String ) => sentence.split( " " ).toList
val length = ( ws :List[String] ) => for( w <- ws ) yield w.length
val filter = ( predicate: Int => Boolean ) => ( xs :List[Int] ) => ...
val even = ( i :Int ) => i % 2 == 0
val size = ( xs :List[ _ ] ) => xs.size
val evenWordCount = size o filter( even ) o length o words
Type of evenWordCount : String => Int
Mario Gleichmann 47 JUG Frankfurt / Main
48. Example: Word Counter
val words = ( sentence : String ) => sentence.split( " " ).toList
val length = ( ws :List[String] ) => for( w <- ws ) yield w.length
val filter = ( predicate: Int => Boolean ) => ( xs :List[Int] ) => ...
val even = ( i :Int ) => i % 2 == 0
val size = ( xs :List[ _ ] ) => xs.size
val evenWordCount = size o filter( even ) o length o words
vs.
val evenWordCount = (sentence :String ) =>
size ( filter( even ) ( length( words( sentence ) ) ) )
Mario Gleichmann 48 JUG Frankfurt / Main
49. Example: Word Counter
val words = ( sentence : String ) => sentence.split( " " ).toList
val length = ( ws :List[String] ) => for( w <- ws ) yield w.length
val filter = ( predicate: Int => Boolean ) => ( xs :List[Int] ) => ...
val even = ( i :Int ) => i % 2 == 0
val size = ( xs :List[ _ ] ) => xs.size
val evenWordCount = size o filter( even ) o length o words
evenWordCount( "this sentence contains five even words" )
>> 5
Mario Gleichmann 49 JUG Frankfurt / Main
51. Fundamental Functions
def sum ( list : List[Int] ) : Int = list match {
case Nil => 0
case x :: xs => x + sum( xs )
}
Mario Gleichmann 51 JUG Frankfurt / Main
52. Fundamental Functions
def product ( list : List[Int] ) : Int = list match {
case Nil => 1
case x :: xs => x * product( xs )
}
Mario Gleichmann 52 JUG Frankfurt / Main
53. Fundamental Functions
def allTrue ( ys : List[Boolean] ) : Boolean = ys match {
case Nil => true
case x :: xs => x and allTrue( xs )
}
Mario Gleichmann 53 JUG Frankfurt / Main
54. Fundamental Functions : reduce
def reduce ( list : List[ T ] ) : R = list match {
case Nil => ?
case x :: xs => x ʘ reduce( xs )
}
Mario Gleichmann 54 JUG Frankfurt / Main
55. Fundamental Functions : reduce
def reduce ( list : List[ T ] ) : R = list match {
case Nil => ? 'unit'
case x :: xs => x ʘ reduce( xs )
}
'subsuming operation'
Mario Gleichmann 55 JUG Frankfurt / Main
56. Fundamental Functions : reduce
def reduce[T,R] ( fun : T => R => R ) ( unit : R ) ( list : List[T] ) : R =
list match {
case Nil => unit
case x :: xs => fun ( x ) ( reduce( fun )( unit )( xs ) )
}
Mario Gleichmann 56 JUG Frankfurt / Main
57. Fundamental Functions : reduce
def reduce[T,R] ( fun : T => R => R ) ( unit : R ) ( list : List[T] ) : R =
list match {
case Nil => unit
case x :: xs => fun ( x ) ( reduce( fun )( unit )( xs ) )
}
reduce ʘ unit t1 :: t2 :: t3 :: t4 :: Nil
=>
t1 ʘ ( t2 ʘ ( t3 ʘ ( t4 ʘ unit ) ) )
Mario Gleichmann 57 JUG Frankfurt / Main
58. Fundamental Functions : reduce
val add = (x : Int) => (y : Int) => x + y
val mult = (x : Int) => (y : Int) => x * y
...
val sum = reduce ( add ) ( 0 ) _
val product = reduce ( mult ) ( 1 ) _
...
sum( List( 1, 2, 3, 4 ) ) >> 10
product( List( 1, 2, 3, 4 ) ) >> 24
Mario Gleichmann 58 JUG Frankfurt / Main
59. Fundamental Functions : reduce
val or = ( x :Boolean ) => ( y :Boolean ) => x || y
val and = ( x :Boolean ) => ( y :Boolean ) => x && y
val not = ( x :Boolean ) => !x
...
val existOneTrue = reduce ( or ) ( false ) _
val allFalse = not o reduce ( or ) ( false ) _
val allTrue = reduce ( and ) ( true ) _
...
allTrue( List( 1 < 2, 3 == 3, 1 + 1 == 2 ) ) >> true
Mario Gleichmann 59 JUG Frankfurt / Main
64. Example: List concatenation
!
def append[T] (x:T) (xs:List[ _ ]) = x :: xs
val listConcat = flipArgs( reduce ( append ) _ )
listConcat ( List( 1, 2, 3, 4 ) ) ( List( 8, 9 ) ) )
Type of result: List[Any]
Mario Gleichmann 64 JUG Frankfurt / Main
65. Example: List concatenation
def append[T] (x:T) (xs:List[ T ]) = x :: xs
def listConcat[A] ( a: List[A]) ( b: List[A] ) : List[A] =
reduce[ A, List[A] ] ( ( append[A] ) _ ) (b) (a)
listConcat ( List( 1, 2, 3, 4 ) ) ( List( 8, 9 ) ) )
Type of result: List[Int]
Mario Gleichmann 65 JUG Frankfurt / Main
66. More
Fundamental Functions
Mario Gleichmann 66 JUG Frankfurt / Main
67. Fundamental Functions
val doubleAll : List[Int] => List[Int] = _ match {
case Nil => Nil
case y :: ys => y * 2 :: doubleAll( ys )
}
doubleAll( List( 1, 2, 3, 4 ) )
>> List( 2, 4, 6, 8 )
Mario Gleichmann 67 JUG Frankfurt / Main
68. Fundamental Functions
val toLength : List[String] => List[Int] = _ match {
case Nil => Nil
case y :: ys => y.length :: toLength( ys )
}
toLength( List( "a", "ab", "abc", "abcde" ) ) )
>> List( 1, 2, 3, 5 )
Mario Gleichmann 68 JUG Frankfurt / Main
69. Fundamental Functions : map
val map : List[T] => List[R] = _ match {
case Nil => Nil
case y :: ys => f?( y ) :: map( ys )
}
Mario Gleichmann 69 JUG Frankfurt / Main
70. Fundamental Functions : map
def map[T, R] ( f: T => R ) : List[T] => List[R] =
( xs : List[T] ) => xs match {
case Nil => Nil
case y :: ys => f( y ) :: map( f )( ys )
}
Mario Gleichmann 70 JUG Frankfurt / Main
71. Fundamental Functions : map
def map[T, R] ( f: T => R ) : List[T] => List[R] =
( xs : List[T] ) => xs match {
case Nil => Nil
case y :: ys => f( y ) :: map( f )( ys )
}
Accepting a function to Resulting in another function,
apply on every element accepting the List of elements
Mario Gleichmann 71 JUG Frankfurt / Main
72. Fundamental Functions : map
def map[T, R] ( f: T => R ) : List[T] => List[R] = ...
...
val mult = (x : Int) => (y : Int) => x * y
val doubleAll = map( mult( 2 ) )
...
val toLength = map( ( s :String ) => s.length )
Mario Gleichmann 72 JUG Frankfurt / Main
73. Fundamental Functions : map
val add = (x : Int) => (y : Int) => x + y
val sum = reduce ( add ) ( 0 ) _
val sumMatrix = sum o map( sum )
Type of sum : List[Int] => Int
Type of map( sum ) : List[List[Int]] => List[Int]
Type of sumMatrix : List[List[Int]] => Int
Mario Gleichmann 73 JUG Frankfurt / Main
74. Fundamental Functions : map
val add = (x : Int) => (y : Int) => x + y
val sum = reduce ( add ) ( 0 ) _
val sumMatrix = sum o map( sum )
...
val matrix = List( List( 1, 2, 3 ),
List( 4, 5, 6 ),
List( 7, 8, 9 ) )
sumMatrix( matrix ) >> 45
Mario Gleichmann 74 JUG Frankfurt / Main
75. map via reduce
def applyAndPrepend [A, B] ( f: A => B ) =
( a :A ) => ( bs :List[B] ) => f( a ) :: bs
def map [A, B] ( f: A => B ) : List[A] => List[B] =
reduce ( applyAndPrepend( f ) ) ( Nil ) _
Mario Gleichmann 75 JUG Frankfurt / Main
76. map via reduce
def applyAndPrepend [A, B] ( f: A => B ) =
( a :A ) => ( bs :List[B] ) => f( a ) :: bs
def map [A, B] ( f: A => B ) : List[A] => List[B] =
reduce ( applyAndPrepend( f ) ) ( Nil ) _
f :: f :: f :: f :: Nil
X1 :: X2 :: X3 :: X4 :: Nil
Mario Gleichmann 76 JUG Frankfurt / Main
77. filter via reduce
def filter[T]( pred :T => Boolean ) : List[T] => List[T] =
reduce ( ( x :T ) => ( acc :List[T] ) =>
if( pred( x ) ) x :: acc else acc )
( Nil )
Mario Gleichmann 77 JUG Frankfurt / Main
79. Type Classes
def sum( xs : List[Int] ) : Int = xs match {
case Nil => 0
case head :: tail => head + sum( tail )
}
Mario Gleichmann 79 JUG Frankfurt / Main
80. Type Classes
def sum( xs : List[String] ) : String = xs match {
case Nil => ““
case head :: tail => head + sum( tail )
}
Concatenation !
Mario Gleichmann 80 JUG Frankfurt / Main
81. Type Classes
def sum[A]( xs : List[A] ) : A = xs match {
case Nil => ?
case head :: tail => head ? sum( tail )
}
Mario Gleichmann 81 JUG Frankfurt / Main
82. Type Classes
def sum[A]( xs : List[A] ) : A = xs match {
case Nil => ? 'neutral' element
case head :: tail => head ? sum( tail )
}
element composition
Mario Gleichmann 82 JUG Frankfurt / Main
83. Type Classes
trait SemiGroup[S] {
def add( x : S, y : S ) : S element composition
}
trait Monoid[M] extends SemiGroup[M] {
def unit : M 'neutral' element
}
Mario Gleichmann 83 JUG Frankfurt / Main
84. Type Classes
def sum [A] ( xs : List[A], m: Monoid[A] ) : A =
xs match {
case Nil => m.unit
case head :: tail => m.add( head, sum( tail, m) )
}
Mario Gleichmann 84 JUG Frankfurt / Main
85. Type Classes
def sum [A] ( xs : List[A], m: Monoid[A] ) : A =
'type constraint'
xs match {
case Nil => m.unit
case head :: tail => m.add( head, sum( tail, m) )
}
Mario Gleichmann 85 JUG Frankfurt / Main
86. Type Classes
object IntMonoid extends Monoid[Int]{
def add(x : Int, y : Int): Int = x + y
def unit : Int = 0
}
…
sum( List( 1, 2, 3, 4 ), IntMonoid )
Mario Gleichmann 86 JUG Frankfurt / Main
87. Type Classes
def sum [A] ( xs : List[A] ) ( implicit m: Monoid[A] ) : A = ...
implicit object IntMonoid extends Monoid[Int]{ … }
…
import typeclasses.monoid._
...
sum( List( 1, 2, 3, 4 ) )
Mario Gleichmann 87 JUG Frankfurt / Main
88. Example: Clock-Monoid
sealed abstract case class ClockHour( hour: Int )
case object HOUR_0 extends ClockHour( 0 )
case object HOUR_1 extends ClockHour( 1 )
...
case object HOUR_11 extends ClockHour( 11 )
…
implicit object ClockHourMonoid extends Monoid[ClockHour]{
val hours = Array( HOUR_0, HOUR_1, HOUR_2, ..., HOUR_11 )
def add(x : ClockHour, y : ClockHour) = hours( ( x.hour + y.hour ) % 12 )
def unit : ClockHour = HOUR_0
}
Mario Gleichmann 88 JUG Frankfurt / Main
89. Example: Clock-Monoid
import typeclasses.monoid.ClockHourMonoid
...
sum( List( HOUR_5, HOUR_3, HOUR_8 ) )
>> HOUR_4
Mario Gleichmann 89 JUG Frankfurt / Main
90. Example: Contains element ?
trait Eq[E]{
def equals( e1 :E, e2 :E ) : Boolean
}
def contains [T] ( x :T, xs : List[T] )
( implicit eq :Eq[T] ) : Boolean =
reduce
( ( y :T ) => ( acc :Boolean ) =>
if( eq.equals( x, y ) ) true else acc )
( false ) 1st Arg: 'reducing' function
( xs )
2nd Arg: 'unit'
3rd Arg: List to reduce
Mario Gleichmann 90 JUG Frankfurt / Main
91. Example: Contains element ?
case class Person( name :String, age :Int )
implicit object PersonEq extends Eq[Person]{
def equals( p1 :Person, p2 :Person ) : Boolean =
(p1.name == p2.name) && (p1.age == p2.age)
}
...
val persons = List( Person("Hans", 22),
Person( "Helga", 32 ),
Person( "Hugo", 47 ) )
contains( Person( "Olga", 22 ), persons ) >> false
contains( Person( "Helga", 32 ), persons ) >> true
Mario Gleichmann 91 JUG Frankfurt / Main
93. Monads
A simple Monad: Option
<< abstract >>
Option[+A]
Some[+A] None
presence absence
Handling the or of something
...as the result of a computation
(computational environment)
Mario Gleichmann JUG Frankfurt / Main
94. Monads
A simple Monad: Option
class CustomerDAO{
def findCustomer( custId: Long ) : Option<Customer> = {
...
if( found( customer ) ) Some( customer ) else None
}
}
Mario Gleichmann JUG Frankfurt / Main
95. Monads
A simple Monad: Option
class CustomerDAO{
def findCustomer( custId: Long ) : Option<Customer> = {
...
if( found( customer ) ) Some( customer ) else None
}
}
Explicit Notion, that there may be 'none' result
Mario Gleichmann JUG Frankfurt / Main
96. Monads
A simple Monad: Option
val customerHit = customerDAO.findCustomer( 123 );
...
customerHit match {
case Some( customer ) => println( customer.name )
case None => println( “not found“ )
}
Mario Gleichmann JUG Frankfurt / Main
97. Monads
A simple Monad: Option
val customerHit = customerDAO.findCustomer( 123 );
...
customerHit match {
case Some( customer ) => println( customer.name )
case None => println( “not found“ )
}
Explicit Handling the absensce of a result
Forces 'Awareness'
Mario Gleichmann JUG Frankfurt / Main
98. Monads
A simple Monad: Option
val customerHit = customerDAO.findCustomer( 123 );
...
customerHit match {
case Some( customer ) => println( customer.name )
case None => println( “not found“ )
}
... beside from that ... what's the deal ???
Mario Gleichmann JUG Frankfurt / Main
99. Monads
A simple Monad: Option
val customerHit = customerDAO.findCustomer( 123 );
...
customerHit match {
case Some( customer ) => println( customer.name )
case None => println( “not found“ )
}
'Protected' Function Composition ...
Mario Gleichmann JUG Frankfurt / Main
100. Monads
val projects = Map( "Jan" -> "IKT",
"Joe" -> "TensE",
"Luca" -> "InTA" )
val customers = Map( "IKT" -> "Hanso GmbH",
"InTA" -> "RAIA Duo" )
val cities = Map( "Hanso GmbH" -> "Stuttgart",
"Mogno" -> "Mailand" )
Mario Gleichmann JUG Frankfurt / Main
101. Monads
val projects = Map( "Jan" -> "IKT",
"Joe" -> "TensE",
"Luca" -> "InTA" )
val customers = Map( "IKT" -> "Hanso GmbH",
"InTA" -> "RAIA Duo" )
val cities = Map( "Hanso GmbH" -> "Stuttgart",
"Mogno" -> "Mailand" )
Where is Jan ?
Jan -> IKT -> Hanso GmbH -> Stuttgart
Mario Gleichmann JUG Frankfurt / Main
102. Monads
Jav
public String whereIs( String name ){
a
String project = projects.get( name );
if( project != null ){
String customer = customers.get( project );
if( customer != null ){
String city = cities.get( customer )
if( city != null ) return city;
else return “unknown“;
}
else return ''unknown'';
}
else return ''unknown'';
}
Mario Gleichmann JUG Frankfurt / Main
103. Monads
Scal
A simple Monad: Option
a
def whereIs( name: String ) = {
projects.get( name )
.flatMap( project => customers get project )
.flatMap( customer => cities get customer )
.getOrElse( "unknown!" )
}
Mario Gleichmann JUG Frankfurt / Main
104. Monads
Scal
A simple Monad: Option
a
def whereIs( name: String ) = {
Results in Option[String]
projects.get( name )
.flatMap( project => customers get project )
.flatMap( customer => cities get customer )
.getOrElse( "unknown!" )
}
Mario Gleichmann JUG Frankfurt / Main
105. Monads
Scal
A simple Monad: Option
a
def whereIs( name: String ) = {
Results in Option[String]
projects.get( name )
.flatMap( project => customers get project )
.flatMap( customer => cities get customer )
.getOrElse( "unknown!" )
}
Option[A].map( A => B ) >> Option[B]
Mario Gleichmann JUG Frankfurt / Main
106. Monads
Scal
A simple Monad: Option
a
def whereIs( name: String ) = {
Results in Option[String]
projects.get( name )
.flatMap( project => customers get project )
.flatMap( customer => cities get customer )
.getOrElse( "unknown!" )
}
Option[A].map( A => B ) >> Option[B]
Option[A].map( A => Option[B] ) >> Option[Option[B]]
Mario Gleichmann JUG Frankfurt / Main
107. Monads
Scal
A simple Monad: Option
a
def whereIs( name: String ) = {
Results in Option[String]
projects.get( name )
.flatMap( project => customers get project )
.flatMap( customer => cities get customer )
.getOrElse( "unknown!" )
}
Option[A].map( A => B ) >> Option[B]
Option[A].map( A => Option[B] ) >> Option[Option[B]]
Option[A].flatMap( A => Option[B] ) >> Option[B]
Mario Gleichmann JUG Frankfurt / Main
108. Monads
Protected Composition
map( A => B ) map( B => C ) map( C => D )
None None None
...
Some[A] Some[B] Some[C] Some[D]
Mario Gleichmann JUG Frankfurt / Main
109. Monads
A simple Monad: Option
def whereIs( name: String ) =
( for( project <- projects get name;
customer <- customers get project;
city <- cities get customer
) yield city
).getOrElse( "unknown!" )
Mario Gleichmann JUG Frankfurt / Main
110. Summary
Scala allows for ...
● Currying
● Combinators
● Fundamental Functions
● Type classes
● Monads
Mario Gleichmann JUG Frankfurt / Main
112. 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 112 JUG Frankfurt / Main