|      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" |