Functional Scala II (in practice)

3,549 views

Published on

Published in: Technology

Functional Scala II (in practice)

  1. 1. Functional Scaλa … in Practice 20.10.2010 Java User Group Frankfurt / Main Mario Gleichmann Mario Gleichmann JUG Frankfurt / Main
  2. 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. 3. Summary Mario Gleichmann 3 JUG Frankfurt / Main
  4. 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. 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. 6. Closures 'closing over' var limit = 18 val isAdult = ( age :Int ) => age >= limit 'Closed term' Mario Gleichmann 6 appl JUG Frankfurt / Main
  7. 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. 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. 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. 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. 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. 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
  13. 13. Partial Application Mario Gleichmann 13 JUG Frankfurt / Main
  14. 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. 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. 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. 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. 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
  19. 19. Currying Mario Gleichmann 19 JUG Frankfurt / Main
  20. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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
  32. 32. Combinators Mario Gleichmann 32 JUG Frankfurt / Main
  33. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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
  50. 50. Fundamental Functions Mario Gleichmann 50 JUG Frankfurt / Main
  51. 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. 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. 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. 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. 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. 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. 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. 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. 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
  60. 60. Example: List concatenation def append[T] (x:T) (xs:List[ _ ]) = x :: xs val listConcat = reduce ( append ) _ listConcat ( List( 1, 2, 3, 4 ) ) ( List( 8, 9 ) ) ) >> List( 8, 9, 1, 2, 3, 4 ) listConcat ( List( true, true, false ) ) ( List( true, false ) ) ) >> List( true, false, true, true, false ) Mario Gleichmann 60 JUG Frankfurt / Main
  61. 61. Example: List concatenation def append[T] (x:T) (xs:List[ _ ]) = x :: xs val listConcat = reduce ( append ) _ listConcat ( List( 1, 2, 3, 4 ) ) ( List( 8, 9 ) ) ) >> List( 8, 9, 1, 2, 3, 4 ) 'unit' listConcat ( List( true, true, false ) ) ( List( true, false ) ) ) >> List( true, false, true, true, false ) Mario Gleichmann 61 JUG Frankfurt / Main
  62. 62. 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 ) ) ) >> List( 1, 2, 3, 4, 8, 9 ) listConcat ( List( true, true, false ) ) ( List( true, false ) ) ) >> List( true, true, false, true, false ) Mario Gleichmann 62 JUG Frankfurt / Main
  63. 63. 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 ) ) ) >> List( 1, 2, 3, 4, 8, 9 ) 'unit' listConcat ( List( true, true, false ) ) ( List( true, false ) ) ) >> List( true, true, false, true, false ) Mario Gleichmann 63 JUG Frankfurt / Main
  64. 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. 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. 66. More Fundamental Functions Mario Gleichmann 66 JUG Frankfurt / Main
  67. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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
  78. 78. Type Classes Mario Gleichmann 78 JUG Frankfurt / Main
  79. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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
  92. 92. Monads Mario Gleichmann 92 JUG Frankfurt / Main
  93. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 110. Summary Scala allows for ... ● Currying ● Combinators ● Fundamental Functions ● Type classes ● Monads Mario Gleichmann JUG Frankfurt / Main
  111. 111. Thank you ! Mario Gleichmann 111 JUG Frankfurt / Main
  112. 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

×