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