Functions and Methods Definitions and types n A

  • Slides: 22
Download presentation
Functions and Methods

Functions and Methods

Definitions and types n A function is a piece of code that takes arguments

Definitions and types n A function is a piece of code that takes arguments and returns a result n n 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 n n You “talk” to the object and ask it to run its method More formally, you send a message to the object 2

Syntax n Method (in a class or object): def name (args) = expression n

Syntax n Method (in a class or object): def name (args) = expression n scala> class Person(name: String) { | def double. Name = name * 2 | } defined class Person scala> val jo = new Person("Jo") jo: Person = Person@1 de 9 c 46 d scala> jo. double. Name res 4: String = Jo. Jo n Function: (args) => expression n scala> val mirror = (name: String) => name + name. reverse mirror: String => String = <function 1> scala> mirror("Dave") res 6: String = Daveeva. D 3

Operators and methods n Reminder: Operators are really methods n scala> 2 + 2

Operators and methods n Reminder: Operators are really methods n scala> 2 + 2 res 0: Int = 4 scala> 2. +(2) res 1: Int = 4 n Binary (object + one argument) methods can be treated like operators n scala> List(1, 2, 3, 4). contains(3) res 2: Boolean = true scala> List(1, 2, 3, 4) contains 3 res 3: Boolean = true 4

Function types n Functions are objects, and every object has a type n n

Function types n Functions are objects, and every object has a type n n 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) res 4: (String, Int) => String = <function 3> scala> res 4("paper", 1, 3) res 5: String = ape n So the type of a function is (types of its arguments) => type of its result 5

Anonymous functions n Functions can be given names n n And then they can

Anonymous functions n Functions can be given names n n And then they can be called by name n n scala> val foo = (n: Int) => n * (n - 1) foo: Int => Int = <function 1> scala> foo(5) res 1: Int = 20 But they don’t have to have a name to be called n scala> ((n: Int) => n * (n - 1))(5) res 2: Int = 20 6

Higher-order functions n n A higher-order function is one that either takes one or

Higher-order functions n n 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 n n n 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 n n n n map applies a function to each element of a

map n n n n 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) res 11: Array[Int] = Array(1, 4, 9) scala> Vector(1, 2, 3) map ((x: Int) => x * x) res 12: scala. collection. immutable. Vector[Int] = Vector(1, 4, 9) scala> List(1, 2, 3) map ((x: Int) => x * x) res 13: List[Int] = List(1, 4, 9) scala> Range(1, 6) map ((x: Int) => x * x) res 15: scala. collection. immutable. Indexed. Seq[Int] = Vector(1, 4, 9, 16, 25) scala> (1 until 6) map ((x: Int) => x * x) res 16: scala. collection. immutable. Indexed. Seq[Int] = Vector(1, 4, 9, 16, 25) scala> "boogie" map ((ch: Char) => "aeiou" contains ch) res 17: scala. collection. immutable. Indexed. Seq[Boolean] = Vector(false, true, false, true) 8

More about map n scala> def add. S(str: String) = str + "s" add.

More about map n scala> def add. S(str: String) = str + "s" add. S: (str: String)String scala> List("dog", "cat", "horse") map add. S res 0: List[String] = List(dogs, cats, horses) scala> List(1, 2, 3) map add. S <console>: 9: error: type mismatch; found : String => String required: Int => ? List(1, 2, 3) map add. S ^ scala> def add. S(x: Any) = x + "s" add. S: (x: Any)String scala> List(1, 2, 3) map add. S res 2: List[String] = List(1 s, 2 s, 3 s) 9

filter n filter applies a predicate (Boolean function) to each element of a sequence,

filter n 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) n n scala> List(3, 1, 4, 1, 5, 9) filter ((x: Int) => x > 3) res 0: List[Int] = List(4, 5, 9) scala> "University" filter ((ch: Char) => ch > 'm') res 1: String = nvrsty scala> (2 to 20) filter ((x: Int) => is. Prime(x)) res 9: scala. collection. immutable. Indexed. Seq[Int] = Vector(2, 3, 5, 7, 11, 13, 17, 19) scala> "Scala is a good language". split(" ") filter ((w: String) => w. length >= 5) res 10: Array[String] = Array(Scala, language) 10

reduce n reduce repeatedly applies a binary operation to pairs of elements of a

reduce n reduce repeatedly applies a binary operation to pairs of elements of a sequence, returning a single value n n scala> res 12: scala> res 13: 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) res 15: String = onetwothree Of course, many of these are already supplied by Scala n n n scala> res 16: scala> res 17: scala> res 21: (1 to 10). sum Int = 55 (1 to 10). product Int = 3628800 List("one", "two", "three"). mk. String = onetwothree

Shortcuts n n When you define a method with def, you must specify the

Shortcuts n n 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 n n With a single parameter and an inferred type, you can also leave out the parentheses n n scala> List(3, 1, 4, 1, 5, 9) filter ((x) => x > 3) res 0: List[Int] = List(4, 5, 9) scala> List(3, 1, 4, 1, 5, 9) filter (x => x > 3) res 1: 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 n scala> List(3, 1, 4, 1, 5, 9) filter (_ > 3) res 2: List[Int] = List(4, 5, 9) 12

Splitting lists n n n scala> "one two three" take. While ((ch: Char) =>

Splitting lists n n n scala> "one two three" take. While ((ch: Char) => ch != ' ') res 0: String = one scala> "one two three" take. While (_ != ' ') res 1: String = one scala> "one two three" drop. While (_ != ' ') res 2: String = " two three" scala> "one two three" span (_ != ' ') res 3: (String, String) = (one, " two three") scala> "one two three" partition (_ != ' ') res 4: (String, String) = (onetwothree, " ") scala> List(3, 5, 6, 8, 9) partition (_ % 2 == 0) res 4: (List[Int], List[Int]) = (List(6, 8), List(3, 5, 9)) 13

Testing all elements n sequence. forall(predicate) checks if every element of the sequence satisfies

Testing all elements n sequence. forall(predicate) checks if every element of the sequence satisfies the predicate n n n scala> List(1, 2, 3) forall (_ > 0) res 0: Boolean = true scala> List(1, -2, 3) forall (_ > 0) res 1: Boolean = false sequence. exists(predicate) checks if any element of the sequence satisfies the predicate n n scala> List(1, 2, 3) exists (_ < 0) res 2: Boolean = false scala> List(1, -2, 3) exists (_ < 0) res 3: Boolean = true 14

Extreme underscores n If you have more than one parameter, you can sometimes use

Extreme underscores n If you have more than one parameter, you can sometimes use an underscore for each n n n The first underscore stands for the first parameter, the second underscore for the second parameter, etc. scala> List(5, 3, 4, 2, 1) sort. With (_ < _) res 1: List[Int] = List(1, 2, 3, 4, 5) scala> "This is a list of words". split(" ") sort. With (_. length < _. length) res 2: Array[String] = Array(a, is, of, This, list, words) 15

find n list. find(predicate) returns, as Some(value), the first value in the sequence that

find n 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 n n scala> List(3, 1, 4, 1, 6) find (_ > 3) res 5: Option[Int] = Some(4) scala> List(3, 1, 4, 1, 6) find (_ > 7) res 6: Option[Int] = None scala> "Read the assignment carefully". split(" ") find (_. length > 6) res 7: Option[String] = Some(assignment) I’ll review Option in just a moment 16

find with Strings n scala> val digits = Math. PI. to. String digits: String

find with Strings n scala> val digits = Math. PI. to. String digits: String = 3. 141592653589793 scala> List(3, 1, 4, 1, 6) find (_ > 3) res 0: Option[Int] = Some(4) scala> digits find (_ > 3) res 1: Option[Char] = Some(3) scala> digits find (_ > '3') res 2: Option[Char] = Some(4) scala> 3 == '3' res 3: Boolean = false scala> '3'. to. Int res 4: Int = 51 17

Working with an Option n You can match on an Option n n val

Working with an Option n You can match on an Option n n val opt = men find (x => is. Honest(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 n n n scala> val abc = Some("abc") abc: Some[String] = Some(abc) scala> abc. is. Empty res 5: Boolean = false scala> abc. is. Defined res 6: Boolean = true scala> for (a <- abc) println(a) abc scala> abc get. Or. Else("xyz") res 8: String = abc 18

foreach n Unlike the previously discussed higher-order functions, the return value of foreach is

foreach n Unlike the previously discussed higher-order functions, the return value of foreach is Unit, () n n 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 n n n 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 n A for comprehension is a convenient way to combine a number

for comprehensions n A for comprehension is a convenient way to combine a number of map and filter operations n scala> (1 to 20) filter (is. Prime _) map (x => x * x) res 1: scala. collection. immutable. Indexed. Seq[Int] = Vector(4, 9, 25, 49, 121, 169, 289, 361) scala> for (i <- 1 to 20 if is. Prime(i)) yield (i * i) res 2: scala. collection. immutable. Indexed. Seq[Int] = Vector(4, 9, 25, 49, 121, 169, 289, 361) 20

Why higher-order functions? n Use of higher-order functions makes code shorter and (usually) easier

Why higher-order functions? n Use of higher-order functions makes code shorter and (usually) easier to read n With for comprension: n n scala> (1 to 10) map (x => x * x) res 27: scala. collection. immutable. Indexed. Seq[Int] = Vector(1, 4, 9, 16, 25, 36, 49, 64, 81, 100) Just as a loop: n scala> var v: Vector[Int] = Vector() scala> for (i <- 1 to 10) { | v = v : + i * i | } scala> v res 29: Vector[Int] = Vector(1, 4, 9, 16, 25, 36, 49, 64, 81, 100) n n 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

The End 22