diff -r a623dd1f2898 -r e03a0100ec46 progs/lecture5.scala --- 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