Higher Order Functions (HOFs) and Currying In Scala
November 26, 2019 Leave a comment
Higher Order Functions This takes functions as input parameters and return another function as an output aka HOFs
Note: map, flatMap, filter belongs to HOFs as they take function as an arg
Example
val superFunction: (Int, (String, (Int => Boolean)) => Int) => (Int => Int) = null // Input: (String, (Int => Boolean)) => Int) // function within a function // Output: (Int => Int) // another function which takes Int and returns Int
Currying Functions
Function that applies a given function ‘n’ times over a given value ‘x’
// nTimes(F, n, x) // nTimes(f, 3, x) = f(f(f(x))) = nTimes(f, 2, f(x)) def nTimes(f: (Int => Int), n: Int, x: Int): Int = { if (n == 0) x else nTimes(f, n-1, f(x)) } val adder: Int => Int = _ + 1 val result = nTimes(adder, 10, 0) println(result) // better way of writing it is to return a function that can compute the value // ntb(f, n) = x => f(f(f(....(x)))) def nTimesBetter(f: Int => Int, n: Int): Int => Int = { if (n == 0) (x: Int) => x else (x: Int) => nTimesBetter(f, n-1)(f(x)) } val plus10 = nTimesBetter(adder, 10) println(plus10(0))
Examples on how to consume and return curried functions
def toCurry(f: (Int, Int) => Int): (Int => Int => Int) = x => y => f(x, y) // lambda taking value 'x', returns a lambda taking value 'y' and the result is f(x, y) // It receives a function of type (Int, Int) => Int // It returns a curried function // Note: Looks simple to read but its very hard to think about def fromCurry(f: Int => Int => Int): (Int, Int) => Int = (x, y) => f(x)(y) // TEST // def superAdder2: (Int => Int => Int) = toCurry(_ + _) is same as below one def superAdder2: (Int => Int => Int) = toCurry((x, y) => x + y) def add4 = superAdder2(20) println(add4(7))
Scala supports another kind of curried function by specifying functions with MULTIPLE PARAMETER LISTS
Curried Formats are like PARTIAL FUNCTIONS in JS
Note: For functions with multiple parameters, if we want to define smaller functions later (Line:43) we have to define type on RHS, otherwise it will not compile.
def curriedFormatter(stringFormat: String)(value: Double): String = stringFormat.format(value) val standardFormat: (Double => String) = curriedFormatter("%4.2f") val preciseFormat: (Double => String) = curriedFormatter("%10.8f") println(standardFormat(Math.PI)) println(preciseFormat(Math.PI))
Function Library (Function1 till Function22) has two very important functions that are very useful.
- compose
- fromThen
// genericize the above two functions def compose[A, B, T](f: A => B, g: T => A): T => B = x => f(g(x)) def fromThen[A, B, C](f: A => B, g: B => C): A => C = x => g(f(x)) val add2 = (x: Int) => x + 2 val times3 = (x: Int) => x * 3 val composed = compose(add2, times3) println(composed(4)) // T=4, A=12, B=14 result is 14 val ordered = fromThen(add2, times3) println(ordered(4)) // A=4, B=6, C=18 result is 18
Recent Comments