Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Functional Scala II (in practice)

4,243 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

×