changeset 226 | 5e489c9fe47b |
parent 225 | 56732dbefcff |
child 242 | e6b34f617915 |
225:56732dbefcff | 226:5e489c9fe47b |
---|---|
5 // Polymorphic Types |
5 // Polymorphic Types |
6 //=================== |
6 //=================== |
7 |
7 |
8 // You do not want to write functions like contains, first, |
8 // You do not want to write functions like contains, first, |
9 // length and so on for every type of lists. |
9 // length and so on for every type of lists. |
10 |
|
11 List("one", "two", "three", "four") |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
10 |
26 |
11 |
27 def length_string_list(lst: List[String]): Int = lst match { |
12 def length_string_list(lst: List[String]): Int = lst match { |
28 case Nil => 0 |
13 case Nil => 0 |
29 case x::xs => 1 + length_string_list(xs) |
14 case x::xs => 1 + length_string_list(xs) |
49 def map[A, B](lst: List[A], f: A => B): List[B] = lst match { |
34 def map[A, B](lst: List[A], f: A => B): List[B] = lst match { |
50 case Nil => Nil |
35 case Nil => Nil |
51 case x::xs => f(x)::map(xs, f) |
36 case x::xs => f(x)::map(xs, f) |
52 } |
37 } |
53 |
38 |
54 map(List(1, 2, 3, 4), (x: Int) => x * x) |
39 map(List(1, 2, 3, 4), (x: Int) => x.toString) |
55 |
40 |
56 |
41 |
57 // Remember? |
42 // Remember? |
58 def first[A, B](xs: List[A], f: A => Option[B]) : Option[B] = ... |
43 def first[A, B](xs: List[A], f: A => Option[B]) : Option[B] = ... |
59 |
44 |
61 // distinct / distinctBy |
46 // distinct / distinctBy |
62 |
47 |
63 val ls = List(1,2,3,3,2,4,3,2,1) |
48 val ls = List(1,2,3,3,2,4,3,2,1) |
64 ls.distinct |
49 ls.distinct |
65 |
50 |
51 ls.minBy(_._2) |
|
52 ls.sortBy(_._1) |
|
66 |
53 |
67 def distinctBy[B, C](xs: List[B], |
54 def distinctBy[B, C](xs: List[B], |
68 f: B => C, |
55 f: B => C, |
69 acc: List[C] = Nil): List[B] = xs match { |
56 acc: List[C] = Nil): List[B] = xs match { |
70 case Nil => Nil |
57 case Nil => Nil |
90 |
77 |
91 def id[T](x: T) : T = x |
78 def id[T](x: T) : T = x |
92 |
79 |
93 val x = id(322) // Int |
80 val x = id(322) // Int |
94 val y = id("hey") // String |
81 val y = id("hey") // String |
95 val z = id(Set(1,2,3,4)) // Set[Int] |
82 val z = id(Set[Int](1,2,3,4)) // Set[Int] |
96 |
83 |
97 |
84 |
98 |
85 |
99 // The type variable concept in Scala can get really complicated. |
86 // The type variable concept in Scala can get really complicated. |
100 // |
87 // |
109 |
96 |
110 // Object[] arr = new Integer[10]; |
97 // Object[] arr = new Integer[10]; |
111 // arr[0] = "Hello World"; |
98 // arr[0] = "Hello World"; |
112 |
99 |
113 |
100 |
114 // Scala gives you a compile-time error |
101 // Scala gives you a compile-time error, which |
102 // is much better. |
|
115 |
103 |
116 var arr = Array[Int]() |
104 var arr = Array[Int]() |
117 arr(0) = "Hello World" |
105 arr(0) = "Hello World" |
118 |
106 |
119 |
107 |
120 |
108 |
121 |
109 |
122 |
|
123 |
|
124 // |
110 // |
125 // Object Oriented Programming in Scala |
111 // Object Oriented Programming in Scala |
126 // |
112 // |
127 // ===================================== |
113 // ===================================== |
128 |
114 |
129 abstract class Animal |
115 abstract class Animal |
130 case class Bird(name: String) extends Animal |
116 case class Bird(name: String) extends Animal { |
117 override def toString = name |
|
118 } |
|
131 case class Mammal(name: String) extends Animal |
119 case class Mammal(name: String) extends Animal |
132 case class Reptile(name: String) extends Animal |
120 case class Reptile(name: String) extends Animal |
121 |
|
122 Bird("Sparrow") |
|
133 |
123 |
134 println(Bird("Sparrow")) |
124 println(Bird("Sparrow")) |
135 println(Bird("Sparrow").toString) |
125 println(Bird("Sparrow").toString) |
136 |
126 |
137 |
127 |
140 override def toString = name |
130 override def toString = name |
141 } |
131 } |
142 |
132 |
143 |
133 |
144 // There is a very convenient short-hand notation |
134 // There is a very convenient short-hand notation |
145 // for constructors |
135 // for constructors: |
146 |
136 |
147 class Fraction(x: Int, y: Int) { |
137 class Fraction(x: Int, y: Int) { |
148 def numer = x |
138 def numer = x |
149 def denom = y |
139 def denom = y |
150 } |
140 } |
184 |
174 |
185 |
175 |
186 // ...to allow the notation n + m * i |
176 // ...to allow the notation n + m * i |
187 import scala.language.implicitConversions |
177 import scala.language.implicitConversions |
188 |
178 |
189 object i extends Complex(0, 1) |
179 val i = Complex(0, 1) |
190 implicit def double2complex(re: Double) = Complex(re, 0) |
180 implicit def double2complex(re: Double) = Complex(re, 0) |
191 |
181 |
192 |
182 |
193 val inum1 = -2.0 + -1.5 * i |
183 val inum1 = -2.0 + -1.5 * i |
194 val inum2 = 1.0 + 1.5 * i |
184 val inum2 = 1.0 + 1.5 * i |
220 |
210 |
221 |
211 |
222 |
212 |
223 |
213 |
224 // DFAs in Scala |
214 // DFAs in Scala |
215 //=============== |
|
225 import scala.util.Try |
216 import scala.util.Try |
226 |
217 |
227 |
218 |
228 // A is the state type |
219 // A is the state type |
229 // C is the input (usually characters) |
220 // C is the input (usually characters) |
346 nfa.accepts("aaaaabbbaaa".toList) // false |
337 nfa.accepts("aaaaabbbaaa".toList) // false |
347 nfa.accepts("ac".toList) // false |
338 nfa.accepts("ac".toList) // false |
348 |
339 |
349 |
340 |
350 // Q: Why the kerfuffle about the polymorphic types in DFAs/NFAs? |
341 // Q: Why the kerfuffle about the polymorphic types in DFAs/NFAs? |
351 // A: Subset construction. |
342 // A: Subset construction. Here the state type for the DFA is |
343 // sets of states. |
|
352 |
344 |
353 def subset[A, C](nfa: NFA[A, C]) : DFA[Set[A], C] = { |
345 def subset[A, C](nfa: NFA[A, C]) : DFA[Set[A], C] = { |
354 DFA(nfa.starts, |
346 DFA(nfa.starts, |
355 { case (qs, c) => nfa.nexts(qs, c) }, |
347 { case (qs, c) => nfa.nexts(qs, c) }, |
356 _.exists(nfa.fins)) |
348 _.exists(nfa.fins)) |
391 |
383 |
392 "HAL".increment |
384 "HAL".increment |
393 |
385 |
394 |
386 |
395 |
387 |
396 |
|
397 // Regular expressions - the power of DSLs in Scala |
388 // Regular expressions - the power of DSLs in Scala |
398 //================================================== |
389 //================================================== |
399 |
390 |
400 abstract class Rexp |
391 abstract class Rexp |
401 case object ZERO extends Rexp // nothing |
392 case object ZERO extends Rexp // nothing |
402 case object ONE extends Rexp // the empty string |
393 case object ONE extends Rexp // the empty string |
403 case class CHAR(c: Char) extends Rexp // a character c |
394 case class CHAR(c: Char) extends Rexp // a character c |
404 case class ALT(r1: Rexp, r2: Rexp) extends Rexp // alternative r1 + r2 |
395 case class ALT(r1: Rexp, r2: Rexp) extends Rexp // alternative r1 + r2 |
405 case class SEQ(r1: Rexp, r2: Rexp) extends Rexp // sequence r1 . r2 |
396 case class SEQ(r1: Rexp, r2: Rexp) extends Rexp // sequence r1 . r2 |
406 case class STAR(r: Rexp) extends Rexp // star r* |
397 case class STAR(r: Rexp) extends Rexp // star r* |
407 |
398 |
408 |
399 |
409 |
400 |
410 // (ab)* |
401 // writing (ab)* in the format above is |
402 // tedious |
|
411 val r0 = STAR(SEQ(CHAR('a'), CHAR('b'))) |
403 val r0 = STAR(SEQ(CHAR('a'), CHAR('b'))) |
412 |
404 |
413 |
405 |
414 // some convenience for typing in regular expressions |
406 // some convenience for typing in regular expressions |
415 import scala.language.implicitConversions |
407 import scala.language.implicitConversions |
431 implicit def RexpOps (r: Rexp) = new { |
423 implicit def RexpOps (r: Rexp) = new { |
432 def | (s: Rexp) = ALT(r, s) |
424 def | (s: Rexp) = ALT(r, s) |
433 def % = STAR(r) |
425 def % = STAR(r) |
434 def ~ (s: Rexp) = SEQ(r, s) |
426 def ~ (s: Rexp) = SEQ(r, s) |
435 } |
427 } |
428 |
|
436 |
429 |
437 implicit def stringOps (s: String) = new { |
430 implicit def stringOps (s: String) = new { |
438 def | (r: Rexp) = ALT(s, r) |
431 def | (r: Rexp) = ALT(s, r) |
439 def | (r: String) = ALT(s, r) |
432 def | (r: String) = ALT(s, r) |
440 def % = STAR(s) |
433 def % = STAR(s) |
450 |
443 |
451 |
444 |
452 // Lazy Evaluation |
445 // Lazy Evaluation |
453 //================= |
446 //================= |
454 // |
447 // |
455 // do not evaluate arguments just yet |
448 // Do not evaluate arguments just yet: |
449 // this uses the => in front of the type |
|
450 // of the code-argument |
|
456 |
451 |
457 def time_needed[T](i: Int, code: => T) = { |
452 def time_needed[T](i: Int, code: => T) = { |
458 val start = System.nanoTime() |
453 val start = System.nanoTime() |
459 for (j <- 1 to i) code |
454 for (j <- 1 to i) code |
460 val end = System.nanoTime() |
455 val end = System.nanoTime() |
466 |
461 |
467 ("a" * 10 ++ "b").matches(evil) |
462 ("a" * 10 ++ "b").matches(evil) |
468 ("a" * 10).matches(evil) |
463 ("a" * 10).matches(evil) |
469 ("a" * 10000).matches(evil) |
464 ("a" * 10000).matches(evil) |
470 ("a" * 20000).matches(evil) |
465 ("a" * 20000).matches(evil) |
471 |
466 ("a" * 50000).matches(evil) |
472 time_needed(2, ("a" * 10000).matches(evil)) |
467 |
468 time_needed(1, ("a" * 50000).matches(evil)) |