Presentation is loading. Please wait.

Presentation is loading. Please wait.

Getting Functional.

Similar presentations


Presentation on theme: "Getting Functional."— Presentation transcript:

1 Getting Functional

2 Functional Programming (FP) in Scala
In FP, Functions are first-class objects. That is, they are values, just like other objects are values, and can be treated as such Functions can be assigned to variables, passed as parameters to higher-order functions, returned as results of functions There is some way to write function literals Functions should only transform their inputs into their outputs A function should have no side effects It should not do any input/output It should not change any state (any external data) Given the same inputs, a function should produce the same outputs, every time--it is deterministic If a function is side-effect free and deterministic, it has referential transparency—all calls to the function could be replaced in the program text by the result of the function But we need random numbers, date and time, etc. 2

3 Creating Lists scala> List('a', 'b', 'c')
res0: List[Char] = List(a, b, c) scala> "abc" toList res1: List[Char] = List(a, b, c) scala> "Welcome to Scala" split(" ") res2: Array[java.lang.String] = Array(Welcome, to, Scala) scala> val scala = "Scala" toList scala: List[Char] = List(S, c, a, l, a) scala> "Hello" :: scala res3: List[Any] = List(Hello, S, c, a, l, a) 3

4 Nil and :: scala> List() res4: List[Nothing] = List() scala> Nil
res5: scala.collection.immutable.Nil.type = List() scala> List() == Nil res6: Boolean = true scala> List[String]() res7: List[String] = List() scala> "xyz" :: Nil res8: List[java.lang.String] = List(xyz) scala> "abc" :: "xyz" :: Nil res9: List[java.lang.String] = List(abc, xyz) 4

5 head, tail, and isEmpty scala> val penn = "Pennsylvania" toList
penn: List[Char] = List(P, e, n, n, s, y, l, v, a, n, i, a) scala> penn head res10: Char = P scala> penn tail res11: List[Char] = List(e, n, n, s, y, l, v, a, n, i, a) scala> penn isEmpty res12: Boolean = false scala> Nil isEmpty res13: Boolean = true scala> Nil head java.util.NoSuchElementException: head of empty list (plus many more lines!) 5

6 take, drop, and splitAt scala> penn
res16: List[Char] = List(P, e, n, n, s, y, l, v, a, n, i, a) scala> penn take 4 res17: List[Char] = List(P, e, n, n) scala> penn drop 4 res18: List[Char] = List(s, y, l, v, a, n, i, a) scala> penn splitAt 4 res19: (List[Char], List[Char]) = (List(P, e, n, n),List(s, y, l, v, a, n, i, a)) scala> penn.splitAt(4) res20: (List[Char], List[Char]) = (List(P, e, n, n),List(s, y, l, v, a, n, i, a)) 6

7 toString and mkString scala> List(1, 2, 3).toString
res25: String = List(1, 2, 3) scala> List(1, 2, 3).toString == "List(1, 2, 3)" res26: Boolean = true scala> List(1, 2, 3) mkString(" is less than ") res27: String = 1 is less than 2 is less than 3 scala> List(1, 2, 3) mkString("*") res28: String = 1*2*3 scala> List(1, 2, 3) mkString("<: ", "--", " :>") res29: String = <: :> scala> List(1, 2, 3) mkString("(", ", ", ")") res30: String = (1, 2, 3) 7

8 zip and unzip scala> val words = "one two three" split " "
words: Array[java.lang.String] = Array(one, two, three) scala> val numbers = List(1, 2, 3, 4, 5) numbers: List[Int] = List(1, 2, 3, 4, 5) scala> val z = words zip numbers z: Array[(java.lang.String, Int)] = Array((one,1), (two,2), (three,3)) scala> val zz = numbers zip words zz: List[(Int, java.lang.String)] = List((1,one), (2,two), (3,three)) scala> z toMap res31: scala.collection.immutable.Map[java.lang.String,Int] = Map((one,1), (two,2), (three,3)) scala> zz unzip res32: (List[Int], List[java.lang.String]) = (List(1, 2, 3),List(one, two, three)) 8

9 Higher-order functions
The basic syntax of a function literal is parameter_list => function_body A higher-order function is one that takes a function as a parameter, or returns a function as a result scala> val brag = "Scala is great!" toList brag: List[Char] = List(S, c, a, l, a, , i, s, , g, r, e, a, t, !) scala> brag count((ch: Char) => ch == 'a') res34: Int = 3 scala> brag count((ch: Char) => !(ch isLetter)) res35: Int = 3 scala> "Scala is great!".toList.count((ch: Char) => ch < 'f') res36: Int = 9 scala> "aeiou" contains 'e' res37: Boolean = true scala> "Scala is great!".toList.count((ch: Char) => "aeiou" contains ch) res38: Int = 5 9

10 Abbreviations In a literal function, you can usually omit the type (and, if there’s only one parameter, the parentheses) scala> brag res40: List[Char] = List(S, c, a, l, a, , i, s, , g, r, e, a, t, !) scala> brag count((ch: Char) => ch == 'a') res41: Int = 3 scala> brag count (ch => ch == 'a') res42: Int = 3 In fact, if there is only one parameter, used once, you can omit the parameter and the => and just use _ to stand in for the parameter scala> brag count (_ == 'a') res44: Int = 3 You can use underscores to stand for multiple parameters, provided each is used once, and they are used in order scala> (1 to 10).foldLeft(0)(_ + _) res27: Int = 55 10

11 sortWith scala> brag sortWith((x, y) => x < y)
res49: List[Char] = List( , , !, S, a, a, a, c, e, g, i, l, r, s, t) Since there are two parameters, we can use two underscores scala> brag sortWith (_ < _) res50: List[Char] = List( , , !, S, a, a, a, c, e, g, i, l, r, s, t) Order matters! scala> brag sortWith (_ > _) res52: List[Char] = List(t, s, r, l, i, g, e, c, a, a, a, S, !, , ) 11

12 forall and exists Whereas count returns an Int, forall and exists return a Boolean scala> val n = List(3, 1, 4, 1, 6) n: List[Int] = List(3, 1, 4, 1, 6) scala> n forall(x => x < 8) res53: Boolean = true scala> n forall(x => x < 5) res54: Boolean = false scala> n exists(_ < 5) res55: Boolean = true scala> n exists(_ > 8) res56: Boolean = false 12

13 foreach foreach returns the (uninteresting) Unit value
scala> val brag = List("Scala", "is", "great!") brag: List[java.lang.String] = List(Scala, is, great!) scala> brag foreach (println(_)) Scala is great! scala> brag foreach(println) scala> List(3, 1, 4, 1, 6) foreach (x => if (x > 1) println(x)) 3 4 6 13

14 Least upper bound The following list contains only integers:
scala> val list = List(1, 2, 3) list: List[Int] = List(1, 2, 3) Now let’s add a non-integer to it scala> "hello" :: list res0: List[Any] = List(hello, 1, 2, 3) The type of this new list is the lowest class in the hierarchy that is a superclass of all the elements of the list

15 Closures scala> var c = 5 c: Int = 5
scala> val mult = (x: Int) => c * x mult: (Int) => Int = <function1> scala> mult(3) res63: Int = 15 scala> c = 7 c: Int = 7 scala> mult(10) res64: Int = 70 What will happen if we pass the mult function into another function in another context? It continues to “link to” (enclose?) the original variable c, not it’s value 15

16 map map produces a new list by applying the given function to each element of the given list scala> val n = List(1, 2, 3, 4, 5) n: List[Int] = List(1, 2, 3, 4, 5) scala> n map(x => x * x) res65: List[Int] = List(1, 4, 9, 16, 25) scala> n map (_ >= 3) res66: List[Boolean] = List(false, false, true, true, true) 16

17 flatMap flatMap produces a new list by applying the given function to each element of the given list, and “flattening” the result scala> n res70: List[Int] = List(1, 2, 3, 4, 5) scala> n map (x => List(x, x*x)) res72: List[List[Int]] = List(List(1, 1), List(2, 4), List(3, 9), List(4, 16), List(5, 25)) scala> n flatMap(x => List(x, x*x)) res73: List[Int] = List(1, 1, 2, 4, 3, 9, 4, 16, 5, 25) 17

18 filter filter produces a new list consisting of the values that pass the given test scala> n res67: List[Int] = List(1, 2, 3, 4, 5) scala> n filter (_ < 4) res68: List[Int] = List(1, 2, 3) scala> n filter (_ % 2 == 1) res69: List[Int] = List(1, 3, 5) 18

19 Some Map methods These methods have little to do with “being functional,” so think of them as a bonus :-) We’re going to use a map that takes small numbers (1..5) to their squares: scala> val m = Map(1 -> 1, 2 -> 4, 3 -> 9, 4 -> 16, 5 -> 25) m: scala.collection.immutable.Map[Int,Int] = Map((5,25), (1,1), (2,4), (3,9), (4,16)) scala> m(4) res1: Int = 16 scala> m(10) java.util.NoSuchElementException: key not found: and many more lines of error message scala> m.get(4) res3: Option[Int] = Some(16) scala> m.get(10) res4: Option[Int] = None scala> m.get(4) match { | case Some(x) => x | case None => | } res5: Int = 16 19

20 Another Map method Now consider the following carefully: Given that
scala> m res6: scala.collection.immutable.Map[Int,Int] = Map((5,25), (1,1), (2,4), (3,9), (4,16)) scala> m.getOrElse(4, -999) res7: Int = 16 scala> m.getOrElse(10, -999) res8: Int = -999 Now consider the following carefully: Given that scala> "hello" :: List(1, 2, 3) res9: List[Any] = List(hello, 1, 2, 3) What do you think the type and value of the following will be? scala> val x = m.getOrElse(4, "Hello")

21 “Houston, we have a problem.”
scala> val x = m.getOrElse(4, "Hello") x: Any = 16 That’s pretty scary--but it gets worse: scala> x + 1 <console>:8: error: type mismatch; found : Int(1) required: String x ^

22 The End If I were to pick a language to use today other than Java, it would be Scala James Gosling, creator of Java 22


Download ppt "Getting Functional."

Similar presentations


Ads by Google