1 // Scala Lecture 2 |
1 // Scala Lecture 2 |
2 //================= |
2 //================= |
3 |
3 |
4 |
4 |
5 // the pain with overloaded math operations |
|
6 |
|
7 (100 / 4) |
|
8 |
|
9 (100 / 3) |
|
10 |
|
11 (100.toDouble / 3.toDouble) |
|
12 |
|
13 |
|
14 // For-Comprehensions again |
|
15 //========================== |
|
16 |
|
17 def square(n: Int) : Int = n * n |
|
18 |
|
19 for (n <- (1 to 10).toList) yield { |
|
20 val res = square(n) |
|
21 res |
|
22 } |
|
23 |
|
24 // like in functions, the "last" item inside the yield |
|
25 // will be returned; the last item is not necessarily |
|
26 // the last line |
|
27 |
|
28 for (n <- (1 to 10).toList) yield { |
|
29 if (n % 2 == 0) n |
|
30 else square(n) |
|
31 } |
|
32 |
|
33 |
|
34 // ...please, please do not write: |
|
35 val lst = List(1, 2, 3, 4, 5, 6, 7, 8, 9) |
|
36 |
|
37 for (i <- (0 until lst.length).toList) yield square(lst(i)) |
|
38 |
|
39 // this is just so prone to off-by-one errors; |
|
40 // write instead |
|
41 |
|
42 for (e <- lst; if (e % 2) == 0; if (e != 4)) yield square(e) |
|
43 |
|
44 |
|
45 //this works for sets as well |
|
46 val st = Set(1, 2, 3, 4, 5, 6, 7, 8, 9) |
|
47 |
|
48 for (e <- st) yield { |
|
49 if (e < 5) e else square(e) |
|
50 } |
|
51 |
|
52 |
|
53 |
|
54 // Side-Effects |
|
55 //============== |
|
56 |
|
57 // with only a side-effect (no list is produced), |
|
58 // for has no "yield" |
|
59 |
|
60 for (n <- (1 to 10)) println(n) |
|
61 |
|
62 |
|
63 for (n <- (1 to 10)) { |
|
64 print("The number is: ") |
|
65 print(n) |
|
66 print("\n") |
|
67 } |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 // know when to use yield and when not: |
|
73 |
|
74 val test = |
|
75 for (e <- Set(1, 2, 3, 4, 5, 6, 7, 8, 9); if e < 5) yield square(e) |
|
76 |
|
77 |
|
78 |
|
79 // Option type |
5 // Option type |
80 //============= |
6 //============= |
81 |
7 |
82 //in Java, if something unusually happens, you return null; |
8 //in Java if something unusually happens, you return null; |
83 //in Scala you use Option |
9 //in Scala you use Option |
84 // - if the value is present, you use Some(value) |
10 // - if the value is present, you use Some(value) |
85 // - if no value is present, you use None |
11 // - if no value is present, you use None |
86 |
12 |
87 |
13 |
88 List(7,24,3,4,5,6).find(_ < 4) |
14 List(7,2,3,4,5,6).find(_ < 4) |
89 List(5,6,7,8,9).find(_ < 4) |
15 List(5,6,7,8,9).find(_ < 4) |
90 |
16 |
91 List(7,2,3,4,5,6).filter(_ < 4) |
17 |
92 |
18 // Values in types |
93 // some operations on Option's |
19 // |
|
20 // Boolean: |
|
21 // Int: |
|
22 // String: |
|
23 // |
|
24 // Option[String]: |
|
25 // |
|
26 |
94 |
27 |
95 val lst = List(None, Some(1), Some(2), None, Some(3)) |
28 val lst = List(None, Some(1), Some(2), None, Some(3)) |
96 |
29 |
97 lst.flatten |
30 lst.flatten |
98 |
31 |
99 Some(10).get |
32 Some(1).get |
100 None.get |
|
101 |
33 |
102 Some(1).isDefined |
34 Some(1).isDefined |
103 None.isDefined |
35 None.isDefined |
104 |
36 |
105 val ps = List((3, 0), (3, 2), (4, 2), (2, 0), (1, 0), (1, 1)) |
37 val ps = List((3, 0), (3, 2), (4, 2), (2, 0), (1, 0), (1, 1)) |
106 |
38 |
107 for ((x, y) <- ps) yield { |
39 for ((x, y) <- ps) yield { |
108 if (y == 0) None else Some(x / y) |
40 if (y == 0) None else Some(x / y) |
109 } |
41 } |
110 |
42 |
111 // use .getOrElse is for setting a default value |
43 // getOrElse is for setting a default value |
112 |
44 |
113 val lst = List(None, Some(1), Some(2), None, Some(3)) |
45 val lst = List(None, Some(1), Some(2), None, Some(3)) |
114 |
|
115 for (x <- lst) yield x.getOrElse(0) |
46 for (x <- lst) yield x.getOrElse(0) |
116 |
47 |
117 |
48 |
118 |
49 |
119 |
50 |
120 // error handling with Options (no exceptions) |
51 // error handling with Option (no exceptions) |
121 // |
|
122 // Try(....) |
|
123 // |
52 // |
124 // Try(something).getOrElse(what_to_do_in_an_exception) |
53 // Try(something).getOrElse(what_to_do_in_an_exception) |
125 // |
54 // |
126 import scala.util._ |
55 import scala.util._ |
127 |
|
128 Try(1 + 3) |
|
129 Try(9 / 0) |
|
130 |
|
131 Try(9 / 3).getOrElse(42) |
|
132 Try(9 / 0).getOrElse(42) |
|
133 |
|
134 |
|
135 import io.Source |
56 import io.Source |
136 |
57 |
137 val my_url = """https://nms.kcl.ac.uk/christian.urban""" |
58 Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString |
138 //val my_url = """https://nms.kcl.ac.uk/christan.urban""" // misspelled |
59 |
139 |
60 Try(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString).getOrElse("") |
140 Source.fromURL(my_url).mkString |
61 |
141 |
62 Try(Some(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString)).getOrElse(None) |
142 Try(Source.fromURL(my_url).mkString).getOrElse("") |
|
143 |
|
144 Try(Some(Source.fromURL(my_url).mkString)).getOrElse(None) |
|
145 |
|
146 |
63 |
147 // a function that turns strings into numbers |
64 // a function that turns strings into numbers |
148 Integer.parseInt("1234") |
65 Integer.parseInt("12u34") |
149 |
|
150 |
66 |
151 def get_me_an_int(s: String): Option[Int] = |
67 def get_me_an_int(s: String): Option[Int] = |
152 Try(Some(Integer.parseInt(s))).getOrElse(None) |
68 Try(Some(Integer.parseInt(s))).getOrElse(None) |
153 |
69 |
154 val lst = List("12345", "foo", "5432", "bar", "x21") |
70 val lst = List("12345", "foo", "5432", "bar", "x21") |
155 |
|
156 for (x <- lst) yield get_me_an_int(x) |
71 for (x <- lst) yield get_me_an_int(x) |
157 |
72 |
158 // summing all the numbers |
73 // summing all the numbers |
159 val sum = (for (i <- lst) yield get_me_an_int(i)).flatten.sum |
74 val sum = lst.flatMap(get_me_an_int(_)).sum |
160 |
75 |
161 |
76 |
162 // This may not look any better than working with null in Java, but to |
77 // This may not look any better than working with null in Java, but to |
163 // see the value, you have to put yourself in the shoes of the |
78 // see the value, you have to put yourself in the shoes of the |
164 // consumer of the get_me_an_int function, and imagine you didn't |
79 // consumer of the get_me_an_int function, and imagine you didn't |
165 // write that function. |
80 // write that function. |
166 // |
81 // |
167 // In Java, if you didn't write this function, you'd have to depend on |
82 // In Java, if you didn't write this function, you'd have to depend on |
168 // the Javadoc of get_me_an_int. If you didn't look at the Javadoc, |
83 // the Javadoc of the get_me_an_int. If you didn't look at the Javadoc, |
169 // you might not know that get_me_an_int could return a null, and your |
84 // you might not know that get_me_an_int could return a null, and your |
170 // code could potentially throw a NullPointerException. |
85 // code could potentially throw a NullPointerException. |
171 |
86 |
172 |
87 |
|
88 |
173 // even Scala is not immune to problems like this: |
89 // even Scala is not immune to problems like this: |
174 |
90 |
175 List(5,6,7,8,9).indexOf(42) |
91 List(5,6,7,8,9).indexOf(7) |
176 |
92 |
177 |
93 |
178 // ... how are we supposed to know that this returns -1 |
94 |
179 |
95 |
180 |
96 |
181 //other example for options...NaN |
97 // Type abbreviations |
182 val squareRoot: PartialFunction[Double, Double] = { |
98 //==================== |
183 case d: Double if d > 0 => Math.sqrt(d) |
99 |
184 } |
100 // some syntactic convenience |
185 |
101 type Pos = (int, Int) |
186 val list: List[Double] = List(4, 16, 25, -9) |
102 |
187 |
103 type Board = List[List[Int]] |
188 val result = list.map(Math.sqrt) |
104 |
189 // => result: List[Double] = List(2.0, 4.0, 5.0, NaN) |
105 |
190 |
106 |
191 val result = list.collect(squareRoot) |
107 // Implicits |
192 // => result: List[Double] = List(2.0, 4.0, 5.0) |
108 //=========== |
|
109 // |
|
110 // for example adding your own methods to Strings: |
|
111 // imagine you want to increment strings, like |
|
112 // |
|
113 // "HAL".increment |
|
114 // |
|
115 // you can avoid ugly fudges, like a MyString, by |
|
116 // using implicit conversions |
|
117 |
|
118 |
|
119 implicit class MyString(s: String) { |
|
120 def increment = for (c <- s) yield (c + 1).toChar |
|
121 } |
|
122 |
|
123 "HAL".increment |
|
124 |
|
125 |
|
126 // No return in Scala |
|
127 //==================== |
|
128 |
|
129 //You should not use "return" in Scala: |
|
130 // |
|
131 // A return expression, when evaluated, abandons the |
|
132 // current computation and returns to the caller of the |
|
133 // function in which return appears." |
|
134 |
|
135 def sq1(x: Int): Int = x * x |
|
136 def sq2(x: Int): Int = return x * x |
|
137 |
|
138 def sumq(ls: List[Int]): Int = { |
|
139 (for (x <- ls) yield (return x * x)).sum[Int] |
|
140 } |
|
141 |
|
142 sumq(List(1,2,3,4)) |
|
143 |
|
144 |
|
145 // last expression in a function is the return statement |
|
146 def square(x: Int): Int = { |
|
147 println(s"The argument is ${x}.") |
|
148 x * x |
|
149 } |
|
150 |
|
151 |
|
152 |
|
153 // Pattern Matching |
|
154 //================== |
|
155 |
|
156 // A powerful tool which is supposed to come to Java in a few years |
|
157 // time (https://www.youtube.com/watch?v=oGll155-vuQ)...Scala already |
|
158 // has it for many years ;o) |
|
159 |
|
160 // The general schema: |
|
161 // |
|
162 // expression match { |
|
163 // case pattern1 => expression1 |
|
164 // case pattern2 => expression2 |
|
165 // ... |
|
166 // case patternN => expressionN |
|
167 // } |
|
168 |
|
169 |
|
170 |
|
171 |
|
172 // remember |
|
173 val lst = List(None, Some(1), Some(2), None, Some(3)).flatten |
|
174 |
|
175 |
|
176 def my_flatten(xs: List[Option[Int]]): List[Int] = { |
|
177 ... |
|
178 } |
|
179 |
|
180 |
|
181 def my_flatten(lst: List[Option[Int]]): List[Int] = lst match { |
|
182 case Nil => Nil |
|
183 case None::xs => my_flatten(xs) |
|
184 case Some(n)::xs => n::my_flatten(xs) |
|
185 } |
|
186 |
|
187 |
|
188 // another example |
|
189 def get_me_a_string(n: Int): String = n match { |
|
190 case 0 => "zero" |
|
191 case 1 => "one" |
|
192 case 2 => "two" |
|
193 case _ => "many" |
|
194 } |
|
195 |
|
196 get_me_a_string(0) |
|
197 |
|
198 // you can also have cases combined |
|
199 def season(month: String) = month match { |
|
200 case "March" | "April" | "May" => "It's spring" |
|
201 case "June" | "July" | "August" => "It's summer" |
|
202 case "September" | "October" | "November" => "It's autumn" |
|
203 case "December" | "January" | "February" => "It's winter" |
|
204 } |
|
205 |
|
206 println(season("November")) |
|
207 |
|
208 // What happens if no case matches? |
|
209 |
|
210 println(season("foobar")) |
|
211 |
|
212 // fizz buzz |
|
213 def fizz_buzz(n: Int) : String = (n % 3, n % 5) match { |
|
214 case (0, 0) => "fizz buzz" |
|
215 case (0, _) => "fizz" |
|
216 case (_, 0) => "buzz" |
|
217 case _ => n.toString |
|
218 } |
|
219 |
|
220 for (n <- 0 to 20) |
|
221 println(fizz_buzz(n)) |
|
222 |
|
223 |
|
224 // User-defined Datatypes |
|
225 //======================== |
|
226 |
|
227 abstract class Tree |
|
228 case class Node(elem: Int, left: Tree, right: Tree) extends Tree |
|
229 case class Leaf() extends Tree |
|
230 |
|
231 |
|
232 def insert(tr: Tree, n: Int): Tree = tr match { |
|
233 case Leaf() => Node(n, Leaf(), Leaf()) |
|
234 case Node(m, left, right) => |
|
235 if (n == m) Node(m, left, right) |
|
236 else if (n < m) Node(m, insert(left, n), right) |
|
237 else Node(m, left, insert(right, n)) |
|
238 } |
|
239 |
|
240 |
|
241 val t1 = Node(4, Node(2, Leaf(), Leaf()), Node(7, Leaf(), Leaf())) |
|
242 insert(t1, 3) |
|
243 |
|
244 def depth(tr: Tree): Int = tr match { |
|
245 case Leaf() => 0 |
|
246 case Node(_, left, right) => 1 + List(depth(left), depth(right)).max |
|
247 } |
|
248 |
|
249 |
|
250 def balance(tr: Tree): Int = tr match { |
|
251 case Leaf() => 0 |
|
252 case Node(_, left, right) => depth(left) - depth(right) |
|
253 } |
|
254 |
|
255 balance(insert(t1, 3)) |
|
256 |
|
257 // another example |
|
258 |
|
259 abstract class Person |
|
260 case class King() extends Person |
|
261 case class Peer(deg: String, terr: String, succ: Int) extends Person |
|
262 case class Knight(name: String) extends Person |
|
263 case class Peasant(name: String) extends Person |
|
264 case class Clown() extends Person |
|
265 |
|
266 def title(p: Person): String = p match { |
|
267 case King() => "His Majesty the King" |
|
268 case Peer(deg, terr, _) => s"The ${deg} of ${terr}" |
|
269 case Knight(name) => s"Sir ${name}" |
|
270 case Peasant(name) => name |
|
271 } |
|
272 |
|
273 def superior(p1: Person, p2: Person): Boolean = (p1, p2) match { |
|
274 case (King(), _) => true |
|
275 case (Peer(_,_,_), Knight(_)) => true |
|
276 case (Peer(_,_,_), Peasant(_)) => true |
|
277 case (Peer(_,_,_), Clown()) => true |
|
278 case (Knight(_), Peasant(_)) => true |
|
279 case (Knight(_), Clown()) => true |
|
280 case (Clown(), Peasant(_)) => true |
|
281 case _ => false |
|
282 } |
|
283 |
|
284 val people = List(Knight("David"), |
|
285 Peer("Duke", "Norfolk", 84), |
|
286 Peasant("Christian"), |
|
287 King(), |
|
288 Clown()) |
|
289 |
|
290 println(people.sortWith(superior(_, _)).mkString(", ")) |
|
291 |
193 |
292 |
194 |
293 |
195 // Higher-Order Functions |
294 // Higher-Order Functions |
196 //======================== |
295 //======================== |
197 |
296 |
198 // functions can take functions as arguments |
297 // functions can take functions as arguments |
199 |
298 |
200 val lst = (1 to 10).toList |
299 val lst = (1 to 10).toList |
201 |
300 |
202 def even(x: Int) : Boolean = x % 2 == 0 |
301 def even(x: Int): Boolean = x % 2 == 0 |
203 def odd(x: Int) : Boolean = x % 2 == 1 |
302 def odd(x: Int): Boolean = x % 2 == 1 |
204 |
303 |
205 lst.filter(x => even(x) && odd(x)) |
304 lst.filter(x => even(x)) |
206 lst.filter(even(_)) |
305 lst.filter(even(_)) |
207 lst.filter(odd && even) |
306 lst.filter(even) |
208 |
307 |
209 lst.find(_ > 8) |
308 lst.find(_ > 8) |
210 |
309 |
211 // map applies a function to each element of a list |
|
212 |
|
213 def square(x: Int): Int = x * x |
310 def square(x: Int): Int = x * x |
214 |
311 |
215 val lst = (1 to 10).toList |
|
216 lst.map(square) |
312 lst.map(square) |
217 |
313 |
218 lst.map(square).filter(_ > 4) |
314 lst.map(square).filter(_ > 4) |
219 |
315 |
220 lst.map(square).filter(_ > 4).map(square) |
316 lst.map(square).filter(_ > 4).map(square) |
221 |
317 |
222 // map works for most collection types, including sets |
318 // in my collatz.scala |
223 Set(1, 3, 6).map(square).filter(_ > 4) |
319 //(1 to bnd).map(i => (collatz(i), i)).maxBy(_._1) |
224 |
320 |
225 |
321 |
226 val l = List((1, 3),(2, 4),(4, 1),(6, 2)) |
322 // type of functions, for example f: Int => Int |
227 |
323 |
228 l.map(square(_._1)) |
324 def my_map_int(lst: List[Int], f: Int => Int): List[Int] = lst match { |
229 |
325 case Nil => Nil |
230 |
326 case x::xs => f(x)::my_map_int(xs, f) |
231 // Why are functions as arguments useful? |
327 } |
232 // |
328 |
233 // Consider the sum between a and b: |
329 my_map_int(lst, square) |
234 |
|
235 def sumInts(a: Int, b: Int) : Int = |
|
236 if (a > b) 0 else a + sumInts(a + 1, b) |
|
237 |
|
238 |
|
239 sumInts(10, 16) |
|
240 |
|
241 // sum squares |
|
242 def square(n: Int) : Int = n * n |
|
243 |
|
244 def sumSquares(a: Int, b: Int) : Int = |
|
245 if (a > b) 0 else square(a) + sumSquares(a + 1, b) |
|
246 |
|
247 sumSquares(2, 6) |
|
248 |
|
249 |
|
250 // sum factorials |
|
251 def fact(n: Int) : Int = |
|
252 if (n == 0) 1 else n * fact(n - 1) |
|
253 |
|
254 def sumFacts(a: Int, b: Int) : Int = |
|
255 if (a > b) 0 else fact(a) + sumFacts(a + 1, b) |
|
256 |
|
257 sumFacts(2, 6) |
|
258 |
|
259 |
|
260 |
|
261 // You can see the pattern....can we simplify our work? |
|
262 // The type of functions from ints to ints: Int => Int |
|
263 |
|
264 def sum(f: Int => Int, a: Int, b: Int) : Int = { |
|
265 if (a > b) 0 |
|
266 else f(a) + sum(f, a + 1, b) |
|
267 } |
|
268 |
|
269 |
|
270 def sumSquares(a: Int, b: Int) : Int = sum(square, a, b) |
|
271 def sumFacts(a: Int, b: Int) : Int = sum(fact, a, b) |
|
272 |
|
273 // What should we do for sumInts? |
|
274 |
|
275 def id(n: Int) : Int = n |
|
276 def sumInts(a: Int, b: Int) : Int = sum(id, a, b) |
|
277 |
|
278 sumInts(10, 12) |
|
279 |
|
280 |
|
281 // Anonymous Functions: You can also write: |
|
282 |
|
283 def sumCubes(a: Int, b: Int) : Int = sum(x => x * x * x, a, b) |
|
284 def sumSquares(a: Int, b: Int) : Int = sum(x => x * x, a, b) |
|
285 def sumInts(a: Int, b: Int) : Int = sum(x => x, a, b) |
|
286 |
|
287 |
330 |
288 // other function types |
331 // other function types |
289 // |
332 // |
290 // f1: (Int, Int) => Int |
333 // f1: (Int, Int) => Int |
291 // f2: List[String] => Option[Int] |
334 // f2: List[String] => Option[Int] |
292 // ... |
335 // ... |
293 |
336 |
294 |
337 |
295 // an aside: partial application |
338 def sumOf(f: Int => Int, lst: List[Int]): Int = lst match { |
296 |
339 case Nil => 0 |
297 def add(a: Int)(b: Int) : Int = a + b |
340 case x::xs => f(x) + sumOf(f, xs) |
298 def add_abc(a: Int)(b: Int)(c: Int) : Int = a + b + c |
341 } |
299 |
342 |
300 val add2 : Int => Int = add(2) |
343 def sum_squares(lst: List[Int]) = sumOf(square, lst) |
301 add2(5) |
344 def sum_cubes(lst: List[Int]) = sumOf(x => x * x * x, lst) |
302 |
345 |
303 val add2_bc : Int => Int => Int = add_abc(2) |
346 sum_squares(lst) |
304 val add2_9_c : Int => Int = add2_bc(9) |
347 sum_cubes(lst) |
305 |
348 |
306 add2_9_c(10) |
349 // lets try it factorial |
307 |
350 def fact(n: Int): Int = ... |
308 sum(add(2), 0, 2) |
351 |
309 sum(add(10), 0, 2) |
352 def sum_fact(lst: List[Int]) = sumOf(fact, lst) |
310 |
353 sum_fact(lst) |
311 |
354 |
312 |
355 // Avoid being mutable |
313 |
356 //===================== |
314 // some automatic timing in each evaluation |
357 |
315 package wrappers { |
358 // a student showed me... |
316 |
359 import scala.collection.mutable.ListBuffer |
317 object wrap { |
360 |
318 |
361 |
319 def timed[R](block: => R): R = { |
362 |
320 val t0 = System.nanoTime() |
363 def collatz_max(bnd: Long): (Long, Long) = { |
321 val result = block |
364 val colNos = ListBuffer[(Long, Long)]() |
322 println("Elapsed time: " + (System.nanoTime - t0) + "ns") |
365 for (i <- (1L to bnd).toList) colNos += ((collatz(i), i)) |
323 result |
366 colNos.max |
324 } |
367 } |
325 |
368 |
326 def apply[A](a: => A): A = { |
369 def collatz_max(bnd: Long): (Long, Long) = { |
327 timed(a) |
370 (1L to bnd).map((i) => (collatz(i), i)).maxBy(_._1) |
328 } |
371 } |
329 } |
372 |
330 } |
373 //views -> lazy collection |
331 |
374 def collatz_max(bnd: Long): (Long, Long) = { |
332 $intp.setExecutionWrapper("wrappers.wrap") |
375 (1L to bnd).view.map((i) => (collatz(i), i)).maxBy(_._1) |
333 |
376 } |
334 // Iteration |
377 |
335 |
378 // raises a GC exception |
336 def fib(n: Int) : Int = |
379 (1 to 1000000000).filter(_ % 2 == 0).take(10).toList |
337 if (n <= 1) 1 else fib(n - 1) + fib(n - 2) |
380 // ==> java.lang.OutOfMemoryError: GC overhead limit exceeded |
338 |
381 |
339 fib(10) |
382 (1 to 1000000000).view.filter(_ % 2 == 0).take(10).toList |
340 |
383 |
341 |
384 |
342 Iterator.iterate((1,1)){ case (n: Int, m: Int) => (n + m, n) }.drop(9).next |
385 |
343 |
386 // Sudoku |
344 |
387 //======== |
345 |
|
346 |
|
347 // Function Composition |
|
348 //====================== |
|
349 |
|
350 // How can be Higher-Order Functions and Options be helpful? |
|
351 |
|
352 def add_footer(msg: String) : String = msg ++ " - Sent from iOS" |
|
353 |
|
354 def valid_msg(msg: String) : Boolean = msg.size <= 140 |
|
355 |
|
356 def duplicate(s: String) : String = s ++ s |
|
357 |
|
358 // they compose very nicely, e.g |
|
359 |
|
360 valid_msg(add_footer("Hello World")) |
|
361 valid_msg(duplicate(duplicate(add_footer("Helloooooooooooooooooo World")))) |
|
362 |
|
363 // but not all functions do |
|
364 // first_word: let's first do it the ugly Java way using null: |
|
365 |
|
366 def first_word(msg: String) : String = { |
|
367 val words = msg.split(" ") |
|
368 if (words(0) != "") words(0) else null |
|
369 } |
|
370 |
|
371 duplicate(first_word("Hello World")) |
|
372 duplicate(first_word("")) |
|
373 |
|
374 def extended_duplicate(s: String) : String = |
|
375 if (s != null) s ++ s else null |
|
376 |
|
377 extended_duplicate(first_word("")) |
|
378 |
|
379 // but this is against the rules of the game: we do not want |
|
380 // to change duplicate, because first_word might return null |
|
381 |
|
382 |
|
383 // Avoid always null! |
|
384 def better_first_word(msg: String) : Option[String] = { |
|
385 val words = msg.split(" ") |
|
386 if (words(0) != "") Some(words(0)) else None |
|
387 } |
|
388 |
|
389 better_first_word("Hello World").map(duplicate) |
|
390 |
|
391 better_first_word("Hello World").map(duplicate) |
|
392 better_first_word("").map(duplicate).map(duplicate).map(valid_msg) |
|
393 |
|
394 better_first_word("").map(duplicate) |
|
395 better_first_word("").map(duplicate).map(valid_msg) |
|
396 |
|
397 |
|
398 |
|
399 |
|
400 |
|
401 // Problems with mutability and parallel computations |
|
402 //==================================================== |
|
403 |
|
404 def count_intersection(A: Set[Int], B: Set[Int]) : Int = { |
|
405 var count = 0 |
|
406 for (x <- A; if (B contains x)) count += 1 |
|
407 count |
|
408 } |
|
409 |
|
410 val A = (1 to 1000).toSet |
|
411 val B = (1 to 1000 by 4).toSet |
|
412 |
|
413 count_intersection(A, B) |
|
414 |
|
415 // but do not try to add .par to the for-loop above, |
|
416 // otherwise you will be caught in race-condition hell. |
|
417 |
|
418 |
|
419 //propper parallel version |
|
420 def count_intersection2(A: Set[Int], B: Set[Int]) : Int = |
|
421 A.par.count(x => B contains x) |
|
422 |
|
423 count_intersection2(A, B) |
|
424 |
|
425 |
|
426 //for measuring time |
|
427 def time_needed[T](n: Int, code: => T) = { |
|
428 val start = System.nanoTime() |
|
429 for (i <- (0 to n)) code |
|
430 val end = System.nanoTime() |
|
431 (end - start) / 1.0e9 |
|
432 } |
|
433 |
|
434 val A = (1 to 1000000).toSet |
|
435 val B = (1 to 1000000 by 4).toSet |
|
436 |
|
437 time_needed(10, count_intersection(A, B)) |
|
438 time_needed(10, count_intersection2(A, B)) |
|
439 |
|
440 |
|
441 |
|
442 |
|
443 |
|
444 |
|
445 // No returns in Scala |
|
446 //==================== |
|
447 |
|
448 // You should not use "return" in Scala: |
|
449 // |
|
450 // A return expression, when evaluated, abandons the |
|
451 // current computation and returns to the caller of the |
|
452 // function in which return appears." |
|
453 |
|
454 def sq1(x: Int): Int = x * x |
|
455 def sumq(ls: List[Int]): Int = |
|
456 ls.map(x => x * x).sum |
|
457 |
|
458 |
|
459 |
|
460 |
|
461 def sq2(x: Int): Int = return x * x |
|
462 |
|
463 def sumq(ls: List[Int]): Int = { |
|
464 ls.map(sq1).sum[Int] |
|
465 } |
|
466 |
|
467 sumq(List(1, 2, 3, 4)) |
|
468 |
|
469 |
|
470 |
|
471 def sumq(ls: List[Int]): Int = { |
|
472 val sqs : List[Int] = for (x <- ls) yield (return x * x) |
|
473 sqs.sum |
|
474 } |
|
475 |
|
476 sumq(List(1, 2, 3, 4)) |
|
477 |
|
478 |
|
479 |
|
480 // Type abbreviations |
|
481 //==================== |
|
482 |
|
483 // some syntactic convenience |
|
484 |
|
485 type Pos = (int, Int) |
|
486 type Board = List[List[Int]] |
|
487 |
|
488 |
|
489 |
|
490 |
|
491 // Sudoku in Scala |
|
492 //================= |
|
493 |
388 |
494 // THE POINT OF THIS CODE IS NOT TO BE SUPER |
389 // THE POINT OF THIS CODE IS NOT TO BE SUPER |
495 // EFFICIENT AND FAST, just explaining exhaustive |
390 // EFFICIENT AND FAST, just explaining exhaustive |
496 // depth-first search |
391 // depth-first search |
497 |
392 |