1 // Scala Lecture 5 |
1 // Scala Lecture 5 |
2 //================= |
2 //================= |
3 |
3 |
4 // (Immutable) |
4 // extension methods |
|
5 // implicit conversions |
|
6 // (Immutable) OOP |
|
7 |
|
8 // Cool Stuff in Scala |
|
9 //===================== |
|
10 |
|
11 |
|
12 // Extensions or How to Pimp your Library |
|
13 //====================================== |
|
14 // |
|
15 // For example adding your own methods to Strings: |
|
16 // Imagine you want to increment strings, like |
|
17 // |
|
18 // "HAL".increment |
|
19 // |
|
20 // you can avoid ugly fudges, like a MyString, by |
|
21 // using implicit conversions. |
|
22 |
|
23 extension (s: String) { |
|
24 def increment = s.map(c => (c + 1).toChar) |
|
25 } |
|
26 |
|
27 "HAL".increment |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 import scala.concurrent.duration.{TimeUnit,SECONDS,MINUTES} |
|
33 |
|
34 case class Duration(time: Long, unit: TimeUnit) { |
|
35 def +(o: Duration) = |
|
36 Duration(time + unit.convert(o.time, o.unit), unit) |
|
37 } |
|
38 |
|
39 extension (that: Int) { |
|
40 def seconds = Duration(that, SECONDS) |
|
41 def minutes = Duration(that, MINUTES) |
|
42 } |
|
43 |
|
44 2.minutes + 60.seconds |
|
45 5.seconds + 2.minutes //Duration(125, SECONDS ) |
|
46 |
|
47 |
|
48 // Regular expressions - the power of DSLs in Scala |
|
49 // and Laziness |
|
50 //================================================== |
|
51 |
|
52 abstract class Rexp |
|
53 case object ZERO extends Rexp // nothing |
|
54 case object ONE extends Rexp // the empty string |
|
55 case class CHAR(c: Char) extends Rexp // a character c |
|
56 case class ALT(r1: Rexp, r2: Rexp) extends Rexp // alternative r1 + r2 |
|
57 case class SEQ(r1: Rexp, r2: Rexp) extends Rexp // sequence r1 . r2 |
|
58 case class STAR(r: Rexp) extends Rexp // star r* |
|
59 |
|
60 |
|
61 // some convenience for typing in regular expressions |
|
62 import scala.language.implicitConversions |
|
63 import scala.language.reflectiveCalls |
|
64 |
|
65 def charlist2rexp(s: List[Char]): Rexp = s match { |
|
66 case Nil => ONE |
|
67 case c::Nil => CHAR(c) |
|
68 case c::s => SEQ(CHAR(c), charlist2rexp(s)) |
|
69 } |
|
70 |
|
71 given Conversion[String, Rexp] = (s => charlist2rexp(s.toList)) |
|
72 |
|
73 extension (r: Rexp) { |
|
74 def | (s: Rexp) = ALT(r, s) |
|
75 def % = STAR(r) |
|
76 def ~ (s: Rexp) = SEQ(r, s) |
|
77 } |
|
78 |
|
79 |
|
80 |
|
81 //example regular expressions |
|
82 val digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" |
|
83 val sign = "+" | "-" | "" |
|
84 val number = sign ~ digit ~ digit.% |
|
85 |
|
86 |
|
87 |
|
88 |
5 // Object Oriented Programming in Scala |
89 // Object Oriented Programming in Scala |
6 // ===================================== |
90 // ===================================== |
7 |
91 |
8 |
92 |
9 abstract class Animal |
93 abstract class Animal |
36 class Fraction(x: Int, y: Int) { |
120 class Fraction(x: Int, y: Int) { |
37 def numer = x |
121 def numer = x |
38 def denom = y |
122 def denom = y |
39 } |
123 } |
40 |
124 |
41 val half = new Fraction(1, 2) |
125 val half = Fraction(1, 2) |
42 half.numer |
126 half.numer |
|
127 |
|
128 // does not work with "vanilla" classes |
|
129 half match { |
|
130 case Fraction(x, y) => x / y |
|
131 } |
|
132 |
43 |
133 |
44 case class Fraction(numer: Int, denom: Int) |
134 case class Fraction(numer: Int, denom: Int) |
45 |
135 |
46 val half = Fraction(1, 2) |
136 val half = Fraction(1, 2) |
47 |
137 |
48 half.numer |
138 half.numer |
49 half.denom |
139 half.denom |
|
140 |
|
141 // works with case classes |
|
142 half match { |
|
143 case Fraction(x, y) => x / y |
|
144 } |
50 |
145 |
51 |
146 |
52 // In mandelbrot.scala I used complex (imaginary) numbers |
147 // In mandelbrot.scala I used complex (imaginary) numbers |
53 // and implemented the usual arithmetic operations for complex |
148 // and implemented the usual arithmetic operations for complex |
54 // numbers. |
149 // numbers. |
55 |
150 |
56 case class Complex(re: Double, im: Double) { |
151 case class Complex(re: Double, im: Double) { |
57 // represents the complex number re + im * i |
152 // represents the complex number re + im * i |
58 def foo(that: Complex) = Complex(this.re + that.re, this.im + that.im) |
153 def +(that: Complex) = Complex(this.re + that.re, this.im + that.im) |
59 def -(that: Complex) = Complex(this.re - that.re, this.im - that.im) |
154 def -(that: Complex) = Complex(this.re - that.re, this.im - that.im) |
60 def *(that: Complex) = Complex(this.re * that.re - this.im * that.im, |
155 def *(that: Complex) = Complex(this.re * that.re - this.im * that.im, |
61 this.re * that.im + that.re * this.im) |
156 this.re * that.im + that.re * this.im) |
62 def *(that: Double) = Complex(this.re * that, this.im * that) |
157 def *(that: Double) = Complex(this.re * that, this.im * that) |
63 def abs = Math.sqrt(this.re * this.re + this.im * this.im) |
158 def abs = Math.sqrt(this.re * this.re + this.im * this.im) |
64 } |
159 } |
65 |
160 |
66 object.method(....) |
161 // usual way to reference methods |
67 |
162 //object.method(....) |
68 val test = Complex(1, 2) + Complex (3, 4) |
163 |
|
164 val test = Complex(1, 2) + (Complex (3, 4)) |
|
165 |
69 |
166 |
70 import scala.language.postfixOps |
167 import scala.language.postfixOps |
71 (List(5,4,3,2,1) sorted) reverse |
168 (List(5,4,3,2,1) sorted) reverse |
72 |
169 |
73 // this could have equally been written as |
170 // this could have equally been written as |
82 |
179 |
83 // ...to allow the notation n + m * i |
180 // ...to allow the notation n + m * i |
84 import scala.language.implicitConversions |
181 import scala.language.implicitConversions |
85 |
182 |
86 val i = Complex(0, 1) |
183 val i = Complex(0, 1) |
87 implicit def double2complex(re: Double) = Complex(re, 0) |
184 |
88 |
185 given Conversion[Double, Complex] = (re => Complex(re, 0)) |
89 |
186 |
90 val inum1 = -2.0 + -1.5 * i |
187 val inum1 = -2.0 + -1.5 * i |
91 val inum2 = 1.0 + 1.5 * i |
188 val inum2 = 1.0 + 1.5 * i |
92 |
189 |
93 |
190 |
124 override def toString = numer.toString + "/" + denom.toString |
221 override def toString = numer.toString + "/" + denom.toString |
125 |
222 |
126 def +(other: Fraction) = |
223 def +(other: Fraction) = |
127 Fraction(numer * other.denom + other.numer * denom, |
224 Fraction(numer * other.denom + other.numer * denom, |
128 denom * other.denom) |
225 denom * other.denom) |
129 def *(other: Fraction) = Fraction(numer * other.numer, denom * other.denom) |
226 def *(other: Fraction) = |
|
227 Fraction(numer * other.numer, denom * other.denom) |
130 } |
228 } |
131 |
229 |
132 implicit def Int2Fraction(x: Int) = Fraction(x, 1) |
230 given Conversion[Int, Fraction] = (x => Fraction(x, 1)) |
133 |
231 |
134 val half = Fraction(1, 2) |
232 val half = Fraction(1, 2) |
135 val third = Fraction (1, 3) |
233 val third = Fraction (1, 3) |
136 |
234 |
137 half + third |
235 half + third |
253 subset(nfa).accepts("aaaaab".toList) // true |
351 subset(nfa).accepts("aaaaab".toList) // true |
254 subset(nfa).accepts("aaaaabbb".toList) // true |
352 subset(nfa).accepts("aaaaabbb".toList) // true |
255 subset(nfa).accepts("aaaaabbbaaa".toList) // false |
353 subset(nfa).accepts("aaaaabbbaaa".toList) // false |
256 subset(nfa).accepts("ac".toList) // false |
354 subset(nfa).accepts("ac".toList) // false |
257 |
355 |
258 import scala.math.pow |
|
259 |
|
260 |
356 |
261 // Laziness with style |
357 // Laziness with style |
262 //===================== |
358 //===================== |
263 |
359 |
264 // The concept of lazy evaluation doesn’t really |
360 // The concept of lazy evaluation doesn’t really |
348 def charlist2rexp(s: List[Char]): Rexp = s match { |
444 def charlist2rexp(s: List[Char]): Rexp = s match { |
349 case Nil => ONE |
445 case Nil => ONE |
350 case c::Nil => CHAR(c) |
446 case c::Nil => CHAR(c) |
351 case c::s => SEQ(CHAR(c), charlist2rexp(s)) |
447 case c::s => SEQ(CHAR(c), charlist2rexp(s)) |
352 } |
448 } |
353 implicit def string2rexp(s: String): Rexp = |
449 |
354 charlist2rexp(s.toList) |
450 given Conversion[String, Rexp] = (s => charlist2rexp(s.toList)) |
355 |
451 |
356 implicit def RexpOps (r: Rexp) = new { |
452 extension (r: Rexp) { |
357 def | (s: Rexp) = ALT(r, s) |
453 def | (s: Rexp) = ALT(r, s) |
358 def % = STAR(r) |
454 def % = STAR(r) |
359 def ~ (s: Rexp) = SEQ(r, s) |
455 def ~ (s: Rexp) = SEQ(r, s) |
360 } |
456 } |
361 |
|
362 implicit def stringOps (s: String) = new { |
|
363 def | (r: Rexp) = ALT(s, r) |
|
364 def | (r: String) = ALT(s, r) |
|
365 def % = STAR(s) |
|
366 def ~ (r: Rexp) = SEQ(s, r) |
|
367 def ~ (r: String) = SEQ(s, r) |
|
368 } |
|
369 |
|
370 |
457 |
371 |
458 |
372 |
459 |
373 //example regular expressions |
460 //example regular expressions |
374 val digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" |
461 val digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" |