progs/lecture5.scala
changeset 481 e03a0100ec46
parent 470 86a456f8cb92
child 482 769bda18a43d
--- a/progs/lecture5.scala	Mon Nov 06 21:49:55 2023 +0000
+++ b/progs/lecture5.scala	Fri Dec 08 00:54:36 2023 +0000
@@ -1,7 +1,91 @@
 // Scala Lecture 5
 //=================
 
-// (Immutable)
+// extension methods
+// implicit conversions
+// (Immutable) OOP
+
+// Cool Stuff in Scala
+//=====================
+
+
+// Extensions or How to Pimp your Library
+//======================================
+//
+// For example adding your own methods to Strings:
+// Imagine you want to increment strings, like
+//
+//     "HAL".increment
+//
+// you can avoid ugly fudges, like a MyString, by
+// using implicit conversions.
+
+extension (s: String) {
+  def increment = s.map(c => (c + 1).toChar)
+}
+
+"HAL".increment
+
+
+
+
+import scala.concurrent.duration.{TimeUnit,SECONDS,MINUTES}
+
+case class Duration(time: Long, unit: TimeUnit) {
+  def +(o: Duration) = 
+    Duration(time + unit.convert(o.time, o.unit), unit)
+}
+
+extension (that: Int) {
+  def seconds = Duration(that, SECONDS)
+  def minutes = Duration(that, MINUTES)
+}
+
+2.minutes + 60.seconds
+5.seconds + 2.minutes   //Duration(125, SECONDS )
+
+
+// Regular expressions - the power of DSLs in Scala
+//                                     and Laziness
+//==================================================
+
+abstract class Rexp
+case object ZERO extends Rexp                     // nothing
+case object ONE extends Rexp                      // the empty string
+case class CHAR(c: Char) extends Rexp             // a character c
+case class ALT(r1: Rexp, r2: Rexp) extends Rexp   // alternative  r1 + r2
+case class SEQ(r1: Rexp, r2: Rexp) extends Rexp   // sequence     r1 . r2  
+case class STAR(r: Rexp) extends Rexp             // star         r*
+
+
+// some convenience for typing in regular expressions
+import scala.language.implicitConversions    
+import scala.language.reflectiveCalls 
+
+def charlist2rexp(s: List[Char]): Rexp = s match {
+  case Nil => ONE
+  case c::Nil => CHAR(c)
+  case c::s => SEQ(CHAR(c), charlist2rexp(s))
+}
+
+given Conversion[String, Rexp] = (s => charlist2rexp(s.toList))
+
+extension (r: Rexp) {
+  def | (s: Rexp) = ALT(r, s)
+  def % = STAR(r)
+  def ~ (s: Rexp) = SEQ(r, s)
+}
+
+
+
+//example regular expressions
+val digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
+val sign = "+" | "-" | ""
+val number = sign ~ digit ~ digit.% 
+
+
+
+
 // Object Oriented Programming in Scala
 // =====================================
 
@@ -38,9 +122,15 @@
   def denom = y
 }
 
-val half = new Fraction(1, 2)
+val half = Fraction(1, 2)
 half.numer
 
+// does not work with "vanilla" classes
+half match {
+  case Fraction(x, y) => x / y
+}
+
+
 case class Fraction(numer: Int, denom: Int)
 
 val half = Fraction(1, 2)
@@ -48,6 +138,11 @@
 half.numer
 half.denom
 
+// works with case classes
+half match {
+  case Fraction(x, y) => x / y
+}
+
 
 // In mandelbrot.scala I used complex (imaginary) numbers 
 // and implemented the usual arithmetic operations for complex 
@@ -55,7 +150,7 @@
 
 case class Complex(re: Double, im: Double) { 
   // represents the complex number re + im * i
-  def foo(that: Complex) = Complex(this.re + that.re, this.im + that.im)
+  def +(that: Complex) = Complex(this.re + that.re, this.im + that.im)
   def -(that: Complex) = Complex(this.re - that.re, this.im - that.im)
   def *(that: Complex) = Complex(this.re * that.re - this.im * that.im,
                                  this.re * that.im + that.re * this.im)
@@ -63,9 +158,11 @@
   def abs = Math.sqrt(this.re * this.re + this.im * this.im)
 }
 
-object.method(....)
+// usual way to reference methods
+//object.method(....)
 
-val test = Complex(1, 2) + Complex (3, 4)
+val test = Complex(1, 2) + (Complex (3, 4))
+
 
 import scala.language.postfixOps
 (List(5,4,3,2,1) sorted) reverse
@@ -84,8 +181,8 @@
 import scala.language.implicitConversions   
 
 val i = Complex(0, 1)
-implicit def double2complex(re: Double) = Complex(re, 0)
 
+given Conversion[Double, Complex] = (re => Complex(re, 0))
 
 val inum1 = -2.0 + -1.5 * i
 val inum2 =  1.0 +  1.5 * i
@@ -126,10 +223,11 @@
   def +(other: Fraction) = 
     Fraction(numer * other.denom + other.numer * denom, 
              denom * other.denom)
-  def *(other: Fraction) = Fraction(numer * other.numer, denom * other.denom)
+  def *(other: Fraction) = 
+    Fraction(numer * other.numer, denom * other.denom)
  }
 
-implicit def Int2Fraction(x: Int) = Fraction(x, 1)
+given Conversion[Int, Fraction] = (x => Fraction(x, 1))
 
 val half = Fraction(1, 2)
 val third = Fraction (1, 3)
@@ -255,8 +353,6 @@
 subset(nfa).accepts("aaaaabbbaaa".toList)    // false
 subset(nfa).accepts("ac".toList)             // false
 
-import scala.math.pow
-
 
 // Laziness with style
 //=====================
@@ -350,24 +446,15 @@
   case c::Nil => CHAR(c)
   case c::s => SEQ(CHAR(c), charlist2rexp(s))
 }
-implicit def string2rexp(s: String): Rexp = 
-  charlist2rexp(s.toList)
 
-implicit def RexpOps (r: Rexp) = new {
+given Conversion[String, Rexp] = (s => charlist2rexp(s.toList))
+
+extension (r: Rexp) {
   def | (s: Rexp) = ALT(r, s)
   def % = STAR(r)
   def ~ (s: Rexp) = SEQ(r, s)
 }
 
-implicit def stringOps (s: String) = new {
-  def | (r: Rexp) = ALT(s, r)
-  def | (r: String) = ALT(s, r)
-  def % = STAR(s)
-  def ~ (r: Rexp) = SEQ(s, r)
-  def ~ (r: String) = SEQ(s, r)
-}
-
-
 
 
 //example regular expressions