Functions and Methods Definitions and types  A function is a piece of code that takes arguments and returns a result     A pure function.

Download Report

Transcript Functions and Methods Definitions and types  A function is a piece of code that takes arguments and returns a result     A pure function.

Functions and Methods
Definitions and types

A function is a piece of code that takes arguments and
returns a result




A pure function is a function whose result depends only on
its arguments
You call a function
If called again with the same arguments, a pure function
will return the same result
A method is a function that belongs to an object


You “talk” to the object and ask it to run its method
More formally, you send a message to the object
2
Syntax

Method (in a class or object): def name (args) = expression

scala> class Person(name: String) {
| def doubleName = name * 2
| }
defined class Person
scala> val jo = new Person("Jo")
jo: Person = Person@1de9c46d
scala> jo.doubleName
res4: String = JoJo

Function: (args) => expression

scala> val mirror = (name: String) => name + name.reverse
mirror: String => String = <function1>
scala> mirror("Dave")
res6: String = DaveevaD
3
Operators and methods

Reminder: Operators are really methods

scala> 2 + 2
res0: Int = 4
scala> 2 .+(2)
res1: Int = 4

Binary (object + one argument) methods can be treated like
operators

scala> List(1, 2, 3, 4).contains(3)
res2: Boolean = true
scala> List(1, 2, 3, 4) contains 3
res3: Boolean = true
4
Function types

Functions are objects, and every object has a type

The type of
(name: String) => name + name.reverse
is String => String

scala> (s: String, from: Int, to: Int) =>
s.drop(from).take(to - from + 1)
res4: (String, Int, Int) => String = <function3>
scala> res4("paper", 1, 3)
res5: String = ape

So the type of a function is
(types of its arguments) => type of its result
5
Anonymous functions

Functions can be given names


And then they can be called by name


scala> val foo = (n: Int) => n * (n - 1)
foo: Int => Int = <function1>
scala> foo(5)
res1: Int = 20
But they don’t have to have a name to be called

scala> ((n: Int) => n * (n - 1))(5)
res2: Int = 20
6
Higher-order functions

A higher-order function is one that either takes one or more
functions as arguments, or returns a function as a result, or both

Scala provides a number of higher-order functions, including
the “big three”: map, filter, and reduce



map applies a function to each element of a sequence, returning a
sequence of the results
filter applies a predicate (Boolean function) to each element of a
sequence, and returns a sequence of those elements that satisfy the
predicate (the predicate returns true)
reduce repeatedly applies a binary operation to pairs of elements of a
sequence, returning a single value
map







map applies a function to each element of a sequence, returning a
sequence of the results
scala> Array(1, 2, 3).map((x: Int) => x * x)
res11: Array[Int] = Array(1, 4, 9)
scala> Vector(1, 2, 3) map ((x: Int) => x * x)
res12: scala.collection.immutable.Vector[Int] = Vector(1, 4, 9)
scala> List(1, 2, 3) map ((x: Int) => x * x)
res13: List[Int] = List(1, 4, 9)
scala> Range(1, 6) map ((x: Int) => x * x)
res15: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 4, 9, 16,
25)
scala> (1 until 6) map ((x: Int) => x * x)
res16: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 4, 9, 16,
25)
scala> "boogie" map ((ch: Char) => "aeiou" contains ch)
res17: scala.collection.immutable.IndexedSeq[Boolean] = Vector(false,
true, true, false, true, true)
8
More about map

scala> def addS(str: String) = str + "s"
addS: (str: String)String
scala> List("dog", "cat", "horse") map addS
res0: List[String] = List(dogs, cats, horses)
scala> List(1, 2, 3) map addS
<console>:9: error: type mismatch;
found
: String => String
required: Int => ?
List(1, 2, 3) map addS
^
scala> def addS(x: Any) = x + "s"
addS: (x: Any)String
scala> List(1, 2, 3) map addS
res2: List[String] = List(1s, 2s, 3s)
9
filter

filter applies a predicate (Boolean function) to each element
of a sequence, and returns a sequence of those elements that
satisfy the predicate (the predicate returns true)




scala> List(3, 1, 4, 1, 5, 9) filter ((x: Int) => x > 3)
res0: List[Int] = List(4, 5, 9)
scala> "University" filter ((ch: Char) => ch > 'm')
res1: String = nvrsty
scala> (2 to 20) filter ((x: Int) => isPrime(x))
res9: scala.collection.immutable.IndexedSeq[Int] = Vector(2,
3, 5, 7, 11, 13, 17, 19)
scala> "Scala is a good language".split(" ") filter ((w:
String) => w.length >= 5)
res10: Array[String] = Array(Scala, language)
10
reduce

reduce repeatedly applies a binary operation to pairs of
elements of a sequence, returning a single value




scala>
res12:
scala>
res13:
scala>
(1 to 10) reduce ((x: Int, y: Int) => x + y)
Int = 55
(1 to 10) reduce ((x: Int, y: Int) => x * y)
Int = 3628800
List("one", "two", "three") reduce ((x: String,
y: String) => x + y)
res15: String = onetwothree
Of course, many of these are already supplied by Scala



scala>
res16:
scala>
res17:
scala>
res21:
(1 to 10).sum
Int = 55
(1 to 10).product
Int = 3628800
List("one", "two", "three").mkString
String = onetwothree
Shortcuts


When you define a method with def, you must specify the types of the
parameter
With literal functions, if the parameter type is obvious, you usually don’t need
to specify it


With a single parameter and an inferred type, you can also leave out the
parentheses


scala> List(3, 1, 4, 1, 5, 9) filter ((x) => x > 3)
res0: List[Int] = List(4, 5, 9)
scala> List(3, 1, 4, 1, 5, 9) filter (x => x > 3)
res1: List[Int] = List(4, 5, 9)
In fact, with a single parameter whose type is obvious, you can leave out the
parameter name, and just use an underscore

scala> List(3, 1, 4, 1, 5, 9) filter (_ > 3)
res2: List[Int] = List(4, 5, 9)
12
Splitting lists

scala> "one two three" takeWhile ((ch: Char) => ch != ' ')
res0: String = one

scala> "one two three" takeWhile (_ != ' ')
res1: String = one

scala> "one two three" dropWhile (_ != ' ')
res2: String = " two three"

scala> "one two three" span (_ != ' ')
res3: (String, String) = (one," two three")

scala> "one two three" partition (_ != ' ')
res4: (String, String) = (onetwothree," ")

scala> List(3, 5, 6, 8, 9) partition (_ % 2 == 0)
res4: (List[Int], List[Int]) = (List(6, 8),List(3, 5, 9))
13
Testing all elements

sequence.forall(predicate) checks if every element of the
sequence satisfies the predicate



scala> List(1, 2, 3) forall (_ > 0)
res0: Boolean = true
scala> List(1, -2, 3) forall (_ > 0)
res1: Boolean = false
sequence.exists(predicate) checks if any element of the
sequence satisfies the predicate


scala> List(1, 2, 3) exists (_ < 0)
res2: Boolean = false
scala> List(1, -2, 3) exists (_ < 0)
res3: Boolean = true
14
Extreme underscores

If you have more than one parameter, you can
sometimes use an underscore for each

The first underscore stands for the first parameter, the second
underscore for the second parameter, etc.

scala> List(5, 3, 4, 2, 1) sortWith (_ < _)
res1: List[Int] = List(1, 2, 3, 4, 5)
scala> "This is a list of words".split(" ") sortWith
(_.length < _.length)
res2: Array[String] = Array(a, is, of, This, list,
words)

15
find

list.find(predicate) returns, as Some(value), the first value in
the sequence that satisfies the predicate, or None if no such value
is found




scala> List(3, 1, 4, 1, 6) find (_ > 3)
res5: Option[Int] = Some(4)
scala> List(3, 1, 4, 1, 6) find (_ > 7)
res6: Option[Int] = None
scala> "Read the assignment carefully".split(" ") find
(_.length > 6)
res7: Option[String] = Some(assignment)
I’ll review Option in just a moment
16
find with Strings

scala> val digits = Math.PI.toString
digits: String = 3.141592653589793
scala> List(3, 1, 4, 1, 6) find (_ > 3)
res0: Option[Int] = Some(4)
scala> digits find (_ > 3)
res1: Option[Char] = Some(3)
scala> digits find (_ > '3')
res2: Option[Char] = Some(4)
scala> 3 == '3'
res3: Boolean = false
scala> '3'.toInt
res4: Int = 51
17
Working with an Option

You can match on an Option


val opt = men find (x => isHonest(x))
opt match {
case Some(man) => println(s"$man is an honest man.")
case None => println("Not found.")
}
An Option is a collection (of zero or one thing), so you can use collection
operations on it





scala> val abc = Some("abc")
abc: Some[String] = Some(abc)
scala> abc.isEmpty
res5: Boolean = false
scala> abc.isDefined
res6: Boolean = true
scala> for (a <- abc) println(a)
abc
scala> abc getOrElse("xyz")
res8: String = abc
18
foreach


Unlike the previously discussed higher-order functions, the return value of
foreach is Unit, ()

foreach does something with each element of a sequence, and is used for its
side effects

scala> (1 to 10) foreach (x => print(x * x + " "))
1 4 9 16 25 36 49 64 81 100

scala> var sum = 0; (1 to 10) foreach (x => sum += x * x)
sum: Int = 385
Scala is “multi-paradigm”: It’s object-oriented and functional



Functional languages don’t allow, or at least try to avoid, side effects
The entire purpose of foreach is to have side effects!
If you want to get side effects from a higher-order function, use foreach in
preference to any of the others
19
for comprehensions

A for comprehension is a convenient way to combine a
number of map and filter operations

scala> (1 to 20) filter (isPrime _) map (x => x * x)
res1: scala.collection.immutable.IndexedSeq[Int] =
Vector(4, 9, 25, 49, 121, 169, 289, 361)
scala> for (i <- 1 to 20 if isPrime(i)) yield (i * i)
res2: scala.collection.immutable.IndexedSeq[Int] =
Vector(4, 9, 25, 49, 121, 169, 289, 361)
20
Why higher-order functions?

Use of higher-order functions makes code shorter and (usually) easier to read

With for comprension:


scala> (1 to 10) map (x => x * x)
res27: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 4,
9, 16, 25, 36, 49, 64, 81, 100)
Just as a loop:

scala> var v: Vector[Int] = Vector()
v: Vector[Int] = Vector()
scala> for (i <- 1 to 10) {
|
v = v :+ i * i
| }
scala> v
res29: Vector[Int] = Vector(1, 4, 9, 16, 25, 36, 49, 64, 81, 100)


Higher-order functions make certain tasks much easier
Just like anything else, learning to use higher-order functions easily and
effectively takes practice
21
The End
22