progs/lecture5.scala
changeset 481 e03a0100ec46
parent 470 86a456f8cb92
child 482 769bda18a43d
equal deleted inserted replaced
480:a623dd1f2898 481:e03a0100ec46
     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"