More Functions
- partial applied
- currying
- partial functions
Partial Applied Functions
Partial applied mean that not all the parameters are provided. Then the return type is a new function, which can be used with the rest of parameters
scala> val addFunction = (x: Int, y: Int) => x + y
val addFunction: (Int, Int) => Int = Lambda...
scala> addFunction(7, 8)
val res1: Int = 15
scala> val partialAdd1 = addFunction(7, _: Int)
val partialAdd1: Int => Int = Lambda...
scala> partialAdd1(8)
val res2: Int = 15
scala> val partialAdd2 = (x: Int) => addFunction(x, 7)
val partialAdd2: Int => Int = Lambda...
scala> partialAdd2(8)
val res3: Int = 15
scala> def partialAdd3(x: Int) = addFunction(x, 7)
def partialAdd3(x: Int): Int
scala> partialAdd3(8)
val res4: Int = 15
These are partial applied functions Also methods can be partial applied
scala> def addMethod(x: Int, y: Int): Int = x + y
def addMethod(x: Int, y: Int): Int
scala> addMethod(7, 8)
val res5: Int = 15
scala> val partialAdd4 = addMethod(7, _: Int)
val partialAdd4: Int => Int = Lambda...
scala> partialAdd4(8)
val res6: Int = 15
Currying
scala> def curriedAdd(x: Int)(y: Int) = x + y
def curriedAdd(x: Int)(y: Int): Int
scala> curriedAdd(7)(8)
val res7: Int = 15
scala> val partialAdd5 = curriedAdd(7)
val partialAdd5: Int => Int = Lambda...
scala> partialAdd5(8)
val res8: Int = 15
scala> val partialAdd6 = curriedAdd(7)(_:Int)
val partialAdd6: Int => Int = Lambda...
scala> partialAdd6(8)
val res9: Int = 15
def toCurry(f: (a: Int, b: Int) => Int): Int => Int => Int =
x => y => f(x, y)
def fromCurry(f: Int => Int => Int): (Int, Int) => Int =
(x, y) => f(x)(y)
println(toCurry(_ + _)(2)(3))
println(fromCurry(x => y => x + y)(2, 6))
Function composition
def andThen[A, B, C](f: A => B, g: B => C) =
(a: A) => g(f(a))
def compose[A, B, C](f: B => C, g: A => B ) =
(a: A) => f(g(a))
println(compose((z: Int) => z * 2, (y: Int) => y + 10)(3))
println(andThen[Int, Int, Int](z => z * 2, y => y + 10)(3))
Partial Functions
A partial function is a function applicable to a subset of the data it has been defined for.
For example, we could define a function on the Int domain that only works on positive numbers.
val squareRoot: PartialFunction[Double, Double] =
def apply(x: Double) = Math.sqrt(x)
def isDefinedAt(x: Double) = x >= 0
val squareRoot: PartialFunction[Double, Double] =
case x if x >= 0 => Math.sqrt(x)
OrElse
val negativeToPositive: PartialFunction[Int, Int] =
case x if x <= 0 => Math.abs(x)
val positiveToNegative: PartialFunction[Int, Int] =
case x if x > 0 => -1 * x
val swapSign: PartialFunction[Int, Int] =
positiveToNegative orElse negativeToPositive
val partialPrint: PartialFunction[Int, Unit] = {
case x if x > 0 => println(s"$x is greater then zero")
}
(swapSign andThen partialPrint)(-1)
Collect, map and filter
Collect , map and FIlter can be used with partial functions
val parseRange: PartialFunction[Int, Int] = {
case x: Int if x > 5 => x + 1
}
List(15, 3, "hello") collect { parseRange }
scala> List(1, 2) collect { case i: Int => i > 10 }
val res11: List[Boolean] = List(false, false)
scala> List(1, 2) filter { case i: Int => i > 10 }
val res12: List[Int] = List()
scala> List(1, 2) map { case i: Int if i < 10 => i + 1 }
val res13: List[Int] = List(2, 3)
Here we defined the partial function as an anonymous function.