Functions As Objects

advertisement
Functions As Objects
Literal (“anonymous”) functions



This is a literal number: 3.1416
This is a literal string: "Hello there!"
This is a literal function: (x: Int, y: Int) => x – y


The following are equivalent:




It’s called “anonymous” because we didn’t bother to give it a name
val subtract = (x: Int, y: Int) => x – y
def subtract(x: Int, y: Int) = x – y
Changes: No def, no name, the = changes to => (a “rocket”)
Functions are values, just like numbers are values



They can be saved in variables
They can be passed to methods as arguments
They can be returned from methods as results
2
Example use of functions

scala> def isEven(x: Int) = x % 2 == 0
isEven: (x: Int)Boolean

scala> val isOdd = (x: Int) => x % 2 != 0
isOdd: Int => Boolean = <function1>

scala> def printPassingNumbers(predicate: Int => Boolean) {
|
for (i <- 1 to 10 if predicate(i)) print(i + " ")
|
println
| }
printPassingNumbers: (predicate: Int => Boolean)Unit

scala> printPassingNumbers(isEven)
2 4 6 8 10

scala> printPassingNumbers(isOdd)
1 3 5 7 9
3
When to use anonymous functions

The body of an anonymous function can be a compound
expression (enclosed in { })



scala> printPassingNumbers((n: Int) => {
|
var prime = true
|
for (i <- 2 to n - 1 if n % i == 0) prime = false
|
prime
| })
1 2 3 5 7
This isn’t particularly easy to read
The ideal use of an anonymous function is when:


The function is short and simple
You only need it in one or maybe two places
4
foreach

foreach is an expression that applies a one-argument function
to each value in a sequence (list, vector,…)




Because foreach is a “binary” method, you can use operator
notation


scala> for (i <- List("one", "two")) print(i)
onetwo
scala> List("one", "two").foreach(print)
onetwo
scala> Vector("one", "two").foreach(print)
onetwo
scala> List("one", "two") foreach print
onetwo
The value of a foreach expression is Unit
5
map


map applies a function to each element of a sequence, and returns
a sequence of results

scala> (1 to 10) map ((x: Int) => x * x)
res27: scala.collection.immutable.IndexedSeq[Int] =
Vector(1, 4, 9, 16, 25, 36, 49, 64, 81, 100)

scala> (1 to 10).toList map ((x: Int) => x * x)
res28: List[Int] = List(1, 4, 9, 16, 25, 36, 49, 64,
81, 100)
When possible, map returns the same type of sequence as it was
given
6
filter

filter applies a predicate (test) to each element of a sequence,
and returns a sequence of those values that pass the test


scala> (1 to 10) filter ((x: Int) => x % 3 == 0)
res29: scala.collection.immutable.IndexedSeq[Int] =
Vector(3, 6, 9)
When possible, filter returns the same type of
sequence as it was given
7
reduce

reduce applies a binary operation between each pair of values,
returning a single value as the result

scala> (1 to 10) reduce ((x: Int, y: Int) => x + y)
res31: Int = 55
scala> List(3, 1, 4, 1, 5, 9, 2, 6, 5) reduce ((x:
Int, y: Int) => if (x > y) x else y
res30: Int = 9
8
What’s the point?


Scala provides a lot of higher-order functions that take
functions as arguments
Using these can make your code much shorter and easier to
read

scala> List(3, 1, 4, 1, 5, 9, 2, 6, 5) exists ((x: Int) => x > 5)
res33: Boolean = true
scala> List(3, 1, 4, 1, 5, 9, 2, 6, 5) forall ((x: Int) => x > 5)
res34: Boolean = false
The End
Download