1 // Scala Lecture 5 |
1 // Scala Lecture 5 |
2 //================= |
2 //================= |
3 |
3 |
4 |
4 |
5 |
|
6 // Laziness with style |
5 // Laziness with style |
7 //===================== |
6 //===================== |
8 |
7 |
9 // The concept of lazy evaluation doesn’t really |
8 // The concept of lazy evaluation doesn’t really |
10 // exist in non-functional languages. C-like languages |
9 // exist in non-functional languages. C-like languages |
11 // are strict. To see the difference, consider |
10 // are (sort of) strict. To see the difference, consider |
12 |
11 |
13 def square(x: Int) = x * x |
12 def square(x: Int) = x * x |
14 |
13 |
15 square(42 + 8) |
14 square(42 + 8) |
16 |
15 |
17 // This is called "strict evaluation". |
16 // This is called "strict evaluation". |
18 |
17 |
19 // In contrast, say we have a pretty expensive operation: |
18 // On the contrary, say we have a pretty expensive operation: |
20 |
19 |
21 def peop(n: BigInt): Boolean = peop(n + 1) |
20 def peop(n: BigInt): Boolean = peop(n + 1) |
22 |
21 |
23 val a = "foo" |
22 val a = "foo" |
24 val b = "bar" |
23 val b = "foo" |
25 |
24 |
26 if (a == b || peop(0)) println("true") else println("false") |
25 if (a == b || peop(0)) println("true") else println("false") |
27 |
26 |
28 // This is called "lazy evaluation": |
27 // This is called "lazy evaluation": |
29 // you delay compuation until it is really |
28 // you delay compuation until it is really |
46 s.head #:: generatePrimes(s.tail.filter(_ % s.head != 0)) |
45 s.head #:: generatePrimes(s.tail.filter(_ % s.head != 0)) |
47 |
46 |
48 val primes = generatePrimes(LazyList.from(2)) |
47 val primes = generatePrimes(LazyList.from(2)) |
49 |
48 |
50 // the first 10 primes |
49 // the first 10 primes |
51 primes.take(10).toList |
50 primes.take(100).toList |
52 |
51 |
53 time_needed(1, primes.filter(_ > 100).take(3000).toList) |
52 time_needed(1, primes.filter(_ > 100).take(3000).toList) |
54 time_needed(1, primes.filter(_ > 100).take(3000).toList) |
53 time_needed(1, primes.filter(_ > 100).take(3000).toList) |
55 |
54 |
56 // A Stream (LazyList) of successive numbers: |
55 // A Stream (LazyList) of successive numbers: |
111 def ~ (r: Rexp) = SEQ(s, r) |
110 def ~ (r: Rexp) = SEQ(s, r) |
112 def ~ (r: String) = SEQ(s, r) |
111 def ~ (r: String) = SEQ(s, r) |
113 } |
112 } |
114 |
113 |
115 |
114 |
116 def depth(r: Rexp) : Int = r match { |
115 |
117 case ZERO => 0 |
|
118 case ONE => 0 |
|
119 case CHAR(_) => 0 |
|
120 case ALT(r1, r2) => Math.max(depth(r1), depth(r2)) + 1 |
|
121 case SEQ(r1, r2) => Math.max(depth(r1), depth(r2)) + 1 |
|
122 case STAR(r1) => depth(r1) + 1 |
|
123 } |
|
124 |
116 |
125 //example regular expressions |
117 //example regular expressions |
126 val digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" |
118 val digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" |
127 val sign = "+" | "-" | "" |
119 val sign = "+" | "-" | "" |
128 val number = sign ~ digit ~ digit.% |
120 val number = sign ~ digit ~ digit.% |
155 (for (r1 <- rs; r2 <- rs) yield SEQ(r1, r2)) #::: |
147 (for (r1 <- rs; r2 <- rs) yield SEQ(r1, r2)) #::: |
156 (for (r1 <- rs) yield STAR(r1)) ) |
148 (for (r1 <- rs) yield STAR(r1)) ) |
157 |
149 |
158 |
150 |
159 enum(LazyList(ZERO, ONE, CHAR('a'), CHAR('b'))).take(200).force |
151 enum(LazyList(ZERO, ONE, CHAR('a'), CHAR('b'))).take(200).force |
160 enum(LazyList(ZERO, ONE, CHAR('a'), CHAR('b'))).take(5_000_000) |
152 enum(LazyList(ZERO, ONE, CHAR('a'), CHAR('b'))).take(5_000_000).force |
|
153 |
|
154 |
|
155 def depth(r: Rexp) : Int = r match { |
|
156 case ZERO => 0 |
|
157 case ONE => 0 |
|
158 case CHAR(_) => 0 |
|
159 case ALT(r1, r2) => Math.max(depth(r1), depth(r2)) + 1 |
|
160 case SEQ(r1, r2) => Math.max(depth(r1), depth(r2)) + 1 |
|
161 case STAR(r1) => depth(r1) + 1 |
|
162 } |
161 |
163 |
162 |
164 |
163 val is = |
165 val is = |
164 (enum(LazyList(ZERO, ONE, CHAR('a'), CHAR('b'))) |
166 (enum(LazyList(ZERO, ONE, CHAR('a'), CHAR('b'))) |
165 .dropWhile(depth(_) < 3) |
167 .dropWhile(depth(_) < 3) |
174 // length and so on for every type of lists. |
176 // length and so on for every type of lists. |
175 |
177 |
176 |
178 |
177 def length_string_list(lst: List[String]): Int = lst match { |
179 def length_string_list(lst: List[String]): Int = lst match { |
178 case Nil => 0 |
180 case Nil => 0 |
179 case x::xs => 1 + length_string_list(xs) |
181 case _::xs => 1 + length_string_list(xs) |
180 } |
182 } |
181 |
183 |
182 def length_int_list(lst: List[Int]): Int = lst match { |
184 def length_int_list(lst: List[Int]): Int = lst match { |
183 case Nil => 0 |
185 case Nil => 0 |
184 case x::xs => 1 + length_int_list(xs) |
186 case x::xs => 1 + length_int_list(xs) |
185 } |
187 } |
186 |
188 |
187 length_string_list(List("1", "2", "3", "4")) |
189 length_string_list(List("1", "2", "3", "4")) |
188 length_int_list(List(1, 2, 3, 4)) |
190 length_string_list(List(1, 2, 3, 4)) |
189 |
191 |
190 // you can make the function parametric in type(s) |
192 // you can make the function parametric in type(s) |
191 |
193 |
192 def length[A](lst: List[A]): Int = lst match { |
194 def length[A](lst: List[A]): Int = lst match { |
193 case Nil => 0 |
195 case Nil => 0 |
194 case x::xs => 1 + length(xs) |
196 case x::xs => 1 + length(xs) |
195 } |
197 } |
196 length(List("1", "2", "3", "4")) |
198 length[String](List("1", "2", "3", "4")) |
197 length(List(1, 2, 3, 4)) |
199 length(List(1, 2, 3, 4)) |
198 |
200 |
199 |
201 |
200 def map[A, B](lst: List[A], f: A => B): List[B] = lst match { |
202 def map[A, B](lst: List[A], f: A => B): List[B] = lst match { |
201 case Nil => Nil |
203 case Nil => Nil |
218 f: B => C, |
220 f: B => C, |
219 acc: List[C] = Nil): List[B] = xs match { |
221 acc: List[C] = Nil): List[B] = xs match { |
220 case Nil => Nil |
222 case Nil => Nil |
221 case x::xs => { |
223 case x::xs => { |
222 val res = f(x) |
224 val res = f(x) |
223 if (acc.contains(res)) distinctBy(xs, f, acc) |
225 if (acc.contains(res) distinctBy(xs, f, acc) |
224 else x::distinctBy(xs, f, res::acc) |
226 else x::distinctBy(xs, f, res::acc) |
225 } |
227 } |
226 } |
228 } |
227 |
229 |
228 val cs = List('A', 'b', 'a', 'c', 'B', 'D', 'd') |
230 val cs = List('A', 'b', 'a', 'c', 'B', 'D', 'd') |
240 |
242 |
241 val x = id(322) // Int |
243 val x = id(322) // Int |
242 val y = id("hey") // String |
244 val y = id("hey") // String |
243 val z = id(Set(1,2,3,4)) // Set[Int] |
245 val z = id(Set(1,2,3,4)) // Set[Int] |
244 |
246 |
245 |
247 id[+A, -B] |
246 |
248 |
247 // The type variable concept in Scala can get really complicated. |
249 // The type variable concept in Scala can get really complicated. |
248 // |
250 // |
249 // - variance (OO) |
251 // - variance (OO) |
250 // - bounds (subtyping) |
252 // - bounds (subtyping) |
264 |
266 |
265 var arr = Array[Int]() |
267 var arr = Array[Int]() |
266 arr(0) = "Hello World" |
268 arr(0) = "Hello World" |
267 |
269 |
268 |
270 |
269 |
|
270 // (Immutable) |
271 // (Immutable) |
271 // Object Oriented Programming in Scala |
272 // Object Oriented Programming in Scala |
272 // |
273 // |
273 // ===================================== |
274 // ===================================== |
274 |
275 |
275 abstract class Animal |
276 |
|
277 abstract class Animal |
276 case class Bird(name: String) extends Animal { |
278 case class Bird(name: String) extends Animal { |
277 override def toString = name |
279 override def toString = name |
278 } |
280 } |
279 case class Mammal(name: String) extends Animal |
281 case class Mammal(name: String) extends Animal |
280 case class Reptile(name: String) extends Animal |
282 case class Reptile(name: String) extends Animal |
546 val eight = 0.8 |
546 val eight = 0.8 |
547 val six = 0.6 |
547 val six = 0.6 |
548 |
548 |
549 two - one == one |
549 two - one == one |
550 eight - six == two |
550 eight - six == two |
551 |
551 eight - six |
552 |
552 |
553 |
553 |
554 |
554 // problems about equality and type-errors |
555 List(1, 2, 3).contains("your cup") |
555 |
|
556 List(1, 2, 3).contains("your cup") // should not compile, but retruns false |
|
557 |
|
558 List(1, 2, 3) == Vector(1, 2, 3) // again should not compile, but returns true |
556 |
559 |
557 |
560 |
558 // I like best about Scala that it lets me often write |
561 // I like best about Scala that it lets me often write |
559 // concise, readable code. And it hooks up with the |
562 // concise, readable code. And it hooks up with the |
560 // Isabelle theorem prover. |
563 // Isabelle theorem prover. |
561 |
564 |
562 |
565 |
563 // Puzzlers |
566 // Puzzlers |
564 |
567 |
565 val MONTH = 12 |
568 val month = 12 |
566 val DAY = 24 |
569 val day = 24 |
567 val (HOUR, MINUTE, SECOND) = (12, 0, 0) |
570 val (hour, min, sec) = (12, 0, 0) |
568 |
571 |
569 // use lowercase names for variable |
572 // use lowercase names for variable |
570 |
573 |
571 |
574 |
572 //================== |
575 //================== |
573 val oneTwo = Seq(1, 2, 3).permutations |
576 val oneTwo = Seq(1, 2, 3).permutations |
574 |
577 |
575 if (oneTwo.length > 0) { |
578 if (oneTwo.length > 0) { |
576 println("Permutations of 1 and 2:") |
579 println("Permutations of 1,2 and 3:") |
577 oneTwo.foreach(println) |
580 oneTwo.foreach(println) |
578 } |
581 } |
579 |
582 |
580 val threeFour = Seq(3, 4, 5).permutations |
583 val threeFour = Seq(3, 4, 5).permutations |
581 |
584 |
582 if (!threeFour.isEmpty) { |
585 if (!threeFour.isEmpty) { |
583 println("Permutations of 3 and 4:") |
586 println("Permutations of 3, 4 and 5:") |
584 threeFour.foreach(println) |
587 threeFour.foreach(println) |
585 } |
588 } |
586 |
589 |
587 //================== |
590 //================== |
588 val (a, b, c) = |
591 val (a, b, c) = |