|         |      1 // Scala Lecture 5 | 
|         |      2 //================= | 
|         |      3  | 
|         |      4  | 
|         |      5  | 
|         |      6 // Laziness with style | 
|         |      7 //===================== | 
|         |      8  | 
|         |      9 // The concept of lazy evaluation doesn’t really exist in  | 
|         |     10 // non-functional languages, but it is pretty easy to grasp.  | 
|         |     11 // Consider first  | 
|         |     12  | 
|         |     13 def square(x: Int) = x * x | 
|         |     14  | 
|         |     15 square(42 + 8) | 
|         |     16  | 
|         |     17 // this is called strict evaluation | 
|         |     18  | 
|         |     19 // pretty expensive operation | 
|         |     20 def peop(n: BigInt): Boolean = peop(n + 1)  | 
|         |     21 val a = "foo" | 
|         |     22 val b = "foo" | 
|         |     23  | 
|         |     24 if (a == b || peop(0)) println("true") else println("false") | 
|         |     25  | 
|         |     26 // this is called lazy evaluation | 
|         |     27 // you delay compuation until it is really  | 
|         |     28 // needed; once calculated though, does not  | 
|         |     29 // need to be re-calculated | 
|         |     30  | 
|         |     31 // a useful example is | 
|         |     32 def time_needed[T](i: Int, code: => T) = { | 
|         |     33   val start = System.nanoTime() | 
|         |     34   for (j <- 1 to i) code | 
|         |     35   val end = System.nanoTime() | 
|         |     36   f"${(end - start) / (i * 1.0e9)}%.6f secs" | 
|         |     37 } | 
|         |     38  | 
|         |     39  | 
|         |     40 // streams (I do not care how many) | 
|         |     41 // primes: 2, 3, 5, 7, 9, 11, 13 .... | 
|         |     42  | 
|         |     43 def generatePrimes (s: Stream[Int]): Stream[Int] = | 
|         |     44   s.head #:: generatePrimes(s.tail.filter(_ % s.head != 0)) | 
|         |     45  | 
|         |     46 val primes: Stream[Int] = generatePrimes(Stream.from(2)) | 
|         |     47  | 
|         |     48 // the first 10 primes | 
|         |     49 primes.take(10).toList | 
|         |     50  | 
|         |     51 //primes.filter(_ > 100).take(2000).toList | 
|         |     52  | 
|         |     53 time_needed(1, primes.filter(_ > 100).take(3000).toList) | 
|         |     54 time_needed(1, primes.filter(_ > 100).take(3000).toList) | 
|         |     55  | 
|         |     56  | 
|         |     57 Stream.from(2) | 
|         |     58 Stream.from(2).take(10) | 
|         |     59 Stream.from(2).take(10).print | 
|         |     60 Stream.from(10).take(10).print | 
|         |     61  | 
|         |     62 Stream.from(2).take(10).force | 
|         |     63  | 
|         |     64 // itterative version of the Fibonacci numbers | 
|         |     65 def fibIter(a: BigInt, b: BigInt): Stream[BigInt] = | 
|         |     66   a #:: fibIter(b, a + b) | 
|         |     67  | 
|         |     68  | 
|         |     69 fibIter(1, 1).take(10).force | 
|         |     70 fibIter(8, 13).take(10).force | 
|         |     71  | 
|         |     72 fibIter(1, 1).drop(10000).take(1).print | 
|         |     73  | 
|         |     74  | 
|         |     75 // good for testing | 
|         |     76  | 
|         |     77  | 
|         |     78 // Regular expressions - the power of DSLs in Scala | 
|         |     79 //                                     and Laziness | 
|         |     80 //================================================== | 
|         |     81  | 
|         |     82 abstract class Rexp | 
|         |     83 case object ZERO extends Rexp                     // nothing | 
|         |     84 case object ONE extends Rexp                      // the empty string | 
|         |     85 case class CHAR(c: Char) extends Rexp             // a character c | 
|         |     86 case class ALT(r1: Rexp, r2: Rexp) extends Rexp   // alternative  r1 + r2 | 
|         |     87 case class SEQ(r1: Rexp, r2: Rexp) extends Rexp   // sequence     r1 . r2   | 
|         |     88 case class STAR(r: Rexp) extends Rexp             // star         r* | 
|         |     89  | 
|         |     90  | 
|         |     91  | 
|         |     92 // writing (ab)* in the format above is  | 
|         |     93 // tedious | 
|         |     94 val r0 = STAR(SEQ(CHAR('a'), CHAR('b'))) | 
|         |     95  | 
|         |     96  | 
|         |     97 // some convenience for typing in regular expressions | 
|         |     98 import scala.language.implicitConversions     | 
|         |     99 import scala.language.reflectiveCalls  | 
|         |    100  | 
|         |    101 def charlist2rexp(s: List[Char]): Rexp = s match { | 
|         |    102   case Nil => ONE | 
|         |    103   case c::Nil => CHAR(c) | 
|         |    104   case c::s => SEQ(CHAR(c), charlist2rexp(s)) | 
|         |    105 } | 
|         |    106 implicit def string2rexp(s: String): Rexp =  | 
|         |    107   charlist2rexp(s.toList) | 
|         |    108  | 
|         |    109  | 
|         |    110 val r1 = STAR("ab") | 
|         |    111 val r2 = STAR(ALT("ab", "baa baa black sheep")) | 
|         |    112 val r3 = STAR(SEQ("ab", ALT("a", "b"))) | 
|         |    113  | 
|         |    114 implicit def RexpOps (r: Rexp) = new { | 
|         |    115   def | (s: Rexp) = ALT(r, s) | 
|         |    116   def % = STAR(r) | 
|         |    117   def ~ (s: Rexp) = SEQ(r, s) | 
|         |    118 } | 
|         |    119  | 
|         |    120  | 
|         |    121 implicit def stringOps (s: String) = new { | 
|         |    122   def | (r: Rexp) = ALT(s, r) | 
|         |    123   def | (r: String) = ALT(s, r) | 
|         |    124   def % = STAR(s) | 
|         |    125   def ~ (r: Rexp) = SEQ(s, r) | 
|         |    126   def ~ (r: String) = SEQ(s, r) | 
|         |    127 } | 
|         |    128  | 
|         |    129  | 
|         |    130 def depth(r: Rexp) : Int = r match { | 
|         |    131   case ZERO => 0 | 
|         |    132   case ONE => 0 | 
|         |    133   case CHAR(_) => 0 | 
|         |    134   case ALT(r1, r2) => Math.max(depth(r1), depth(r2)) + 1 | 
|         |    135   case SEQ(r1, r2) => Math.max(depth(r1), depth(r2)) + 1  | 
|         |    136   case STAR(r1) => depth(r1) + 1 | 
|         |    137 } | 
|         |    138  | 
|         |    139 //example regular expressions | 
|         |    140 val digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | 
|         |    141 val sign = "+" | "-" | "" | 
|         |    142 val number = sign ~ digit ~ digit.%  | 
|         |    143  | 
|         |    144 // task: enumerate exhaustively regular expression | 
|         |    145 // starting from small ones towards bigger ones. | 
|         |    146  | 
|         |    147 // 1st idea: enumerate them up to a level | 
|         |    148  | 
|         |    149 def enuml(l: Int, s: String) : Set[Rexp] = l match { | 
|         |    150   case 0 => Set(ZERO, ONE) ++ s.map(CHAR).toSet | 
|         |    151   case n =>   | 
|         |    152     val rs = enuml(n - 1, s) | 
|         |    153     rs ++ | 
|         |    154     (for (r1 <- rs; r2 <- rs) yield ALT(r1, r2)) ++ | 
|         |    155     (for (r1 <- rs; r2 <- rs) yield SEQ(r1, r2)) ++ | 
|         |    156     (for (r1 <- rs) yield STAR(r1)) | 
|         |    157 } | 
|         |    158  | 
|         |    159 enuml(1, "a").size | 
|         |    160 enuml(2, "a").size | 
|         |    161 enuml(3, "a").size // out of heap space | 
|         |    162  | 
|         |    163  | 
|         |    164 def enum(rs: Stream[Rexp]) : Stream[Rexp] =  | 
|         |    165   rs #::: enum( (for (r1 <- rs; r2 <- rs) yield ALT(r1, r2)) #::: | 
|         |    166                 (for (r1 <- rs; r2 <- rs) yield SEQ(r1, r2)) #::: | 
|         |    167                 (for (r1 <- rs) yield STAR(r1)) ) | 
|         |    168  | 
|         |    169  | 
|         |    170 enum(ZERO #:: ONE #:: "ab".toStream.map(CHAR)).take(200).force | 
|         |    171 enum(ZERO #:: ONE #:: "ab".toStream.map(CHAR)).take(200000).force | 
|         |    172  | 
|         |    173  | 
|         |    174 val is =  | 
|         |    175   (enum(ZERO #:: ONE #:: "ab".toStream.map(CHAR)) | 
|         |    176     .dropWhile(depth(_) < 3) | 
|         |    177     .take(10).foreach(println)) | 
|         |    178  | 
|         |    179  | 
|         |    180  | 
|         |    181 // Parsing - The Solved Problem That Isn't | 
|         |    182 //========================================= | 
|         |    183 // | 
|         |    184 // https://tratt.net/laurie/blog/entries/parsing_the_solved_problem_that_isnt.html | 
|         |    185 // | 
|         |    186 // Or, A topic of endless "fun"(?) | 
|         |    187  | 
|         |    188  | 
|         |    189 // input type: String | 
|         |    190 // output type: Int | 
|         |    191 Integer.parseInt("123456") | 
|         |    192  | 
|         |    193 /* Note, in the previous lectures I did not show the type consraint | 
|         |    194  * I <% Seq[_] , which means that the input type I can be | 
|         |    195  * treated, or seen, as a sequence. */ | 
|         |    196  | 
|         |    197 abstract class Parser[I <% Seq[_], T] { | 
|         |    198   def parse(ts: I): Set[(T, I)] | 
|         |    199  | 
|         |    200   def parse_all(ts: I) : Set[T] = | 
|         |    201     for ((head, tail) <- parse(ts);  | 
|         |    202         if (tail.isEmpty)) yield head | 
|         |    203 } | 
|         |    204  | 
|         |    205 // the idea is that a parser can parse something | 
|         |    206 // from the input and leaves something unparsed => pairs | 
|         |    207  | 
|         |    208 class AltParser[I <% Seq[_], T]( | 
|         |    209   p: => Parser[I, T],  | 
|         |    210   q: => Parser[I, T]) extends Parser[I, T] { | 
|         |    211  | 
|         |    212   def parse(sb: I) = p.parse(sb) ++ q.parse(sb)    | 
|         |    213 } | 
|         |    214  | 
|         |    215  | 
|         |    216 class SeqParser[I <% Seq[_], T, S]( | 
|         |    217   p: => Parser[I, T],  | 
|         |    218   q: => Parser[I, S]) extends Parser[I, (T, S)] { | 
|         |    219  | 
|         |    220   def parse(sb: I) =  | 
|         |    221     for ((head1, tail1) <- p.parse(sb);  | 
|         |    222          (head2, tail2) <- q.parse(tail1)) yield ((head1, head2), tail2) | 
|         |    223 } | 
|         |    224  | 
|         |    225  | 
|         |    226 class FunParser[I <% Seq[_], T, S]( | 
|         |    227   p: => Parser[I, T],  | 
|         |    228   f: T => S) extends Parser[I, S] { | 
|         |    229  | 
|         |    230   def parse(sb: I) =  | 
|         |    231     for ((head, tail) <- p.parse(sb)) yield (f(head), tail) | 
|         |    232 } | 
|         |    233  | 
|         |    234  | 
|         |    235 implicit def ParserOps[I<% Seq[_], T](p: Parser[I, T]) = new { | 
|         |    236   def | (q : => Parser[I, T]) = new AltParser[I, T](p, q) | 
|         |    237   def ==>[S] (f: => T => S) = new FunParser[I, T, S](p, f) | 
|         |    238   def ~[S] (q : => Parser[I, S]) = new SeqParser[I, T, S](p, q) | 
|         |    239 } | 
|         |    240  | 
|         |    241 implicit def StringOps(s: String) = new { | 
|         |    242   def | (q : => Parser[String, String]) = new AltParser[String, String](s, q) | 
|         |    243   def | (r: String) = new AltParser[String, String](s, r) | 
|         |    244   def ==>[S] (f: => String => S) = new FunParser[String, String, S](s, f) | 
|         |    245   def ~[S] (q : => Parser[String, S]) =  | 
|         |    246     new SeqParser[String, String, S](s, q) | 
|         |    247   def ~ (r: String) =  | 
|         |    248     new SeqParser[String, String, String](s, r) | 
|         |    249 } | 
|         |    250  | 
|         |    251  | 
|         |    252 // atomic parsers   | 
|         |    253 case class CharParser(c: Char) extends Parser[String, Char] { | 
|         |    254   def parse(sb: String) =  | 
|         |    255     if (sb != "" && sb.head == c) Set((c, sb.tail)) else Set() | 
|         |    256 } | 
|         |    257  | 
|         |    258 import scala.util.matching.Regex | 
|         |    259 case class RegexParser(reg: Regex) extends Parser[String, String] { | 
|         |    260   def parse(sb: String) = reg.findPrefixMatchOf(sb) match { | 
|         |    261     case None => Set() | 
|         |    262     case Some(m) => Set((m.matched, m.after.toString))   | 
|         |    263   } | 
|         |    264 } | 
|         |    265  | 
|         |    266 val NumParser = RegexParser("[0-9]+".r) | 
|         |    267 def StringParser(s: String) = RegexParser(Regex.quote(s).r) | 
|         |    268  | 
|         |    269 println(NumParser.parse_all("12345")) | 
|         |    270 println(NumParser.parse_all("12u45")) | 
|         |    271  | 
|         |    272  | 
|         |    273 // convenience | 
|         |    274 implicit def string2parser(s: String) = StringParser(s) | 
|         |    275 implicit def char2parser(c: Char) = CharParser(c) | 
|         |    276  | 
|         |    277 implicit def ParserOps[I<% Seq[_], T](p: Parser[I, T]) = new { | 
|         |    278   def | (q : => Parser[I, T]) = new AltParser[I, T](p, q) | 
|         |    279   def ==>[S] (f: => T => S) = new FunParser[I, T, S](p, f) | 
|         |    280   def ~[S] (q : => Parser[I, S]) = new SeqParser[I, T, S](p, q) | 
|         |    281 } | 
|         |    282  | 
|         |    283 implicit def StringOps(s: String) = new { | 
|         |    284   def | (q : => Parser[String, String]) = new AltParser[String, String](s, q) | 
|         |    285   def | (r: String) = new AltParser[String, String](s, r) | 
|         |    286   def ==>[S] (f: => String => S) = new FunParser[String, String, S](s, f) | 
|         |    287   def ~[S] (q : => Parser[String, S]) =  | 
|         |    288     new SeqParser[String, String, S](s, q) | 
|         |    289   def ~ (r: String) =  | 
|         |    290     new SeqParser[String, String, String](s, r) | 
|         |    291 } | 
|         |    292  | 
|         |    293  | 
|         |    294 val NumParserInt = NumParser ==> (s => s.toInt) | 
|         |    295  | 
|         |    296 NumParser.parse_all("12345") | 
|         |    297 NumParserInt.parse_all("12345") | 
|         |    298 NumParserInt.parse_all("12u45") | 
|         |    299  | 
|         |    300  | 
|         |    301 // grammar for arithmetic expressions | 
|         |    302 // | 
|         |    303 //  E ::= T + E | T - E | T | 
|         |    304 //  T ::= F * T | F | 
|         |    305 //  F ::= ( E ) | Number | 
|         |    306  | 
|         |    307  | 
|         |    308 lazy val E: Parser[String, Int] =  | 
|         |    309   (T ~ "+" ~ E) ==> { case ((x, y), z) => x + z } | | 
|         |    310   (T ~ "-" ~ E) ==> { case ((x, y), z) => x - z } | T  | 
|         |    311 lazy val T: Parser[String, Int] =  | 
|         |    312   (F ~ "*" ~ T) ==> { case ((x, y), z) => x * z } | F | 
|         |    313 lazy val F: Parser[String, Int] =  | 
|         |    314   ("(" ~ E ~ ")") ==> { case ((x, y), z) => y } | NumParserInt | 
|         |    315  | 
|         |    316 println(E.parse_all("1+3+4")) | 
|         |    317 println(E.parse_all("4*2+3")) | 
|         |    318 println(E.parse_all("4*(2+3)")) | 
|         |    319 println(E.parse_all("(4)*((2+3))")) | 
|         |    320 println(E.parse_all("4/2+3")) | 
|         |    321 println(E.parse_all("(1+2)+3")) | 
|         |    322 println(E.parse_all("1+2+3"))  | 
|         |    323  | 
|         |    324  | 
|         |    325  | 
|         |    326  | 
|         |    327  | 
|         |    328 // The End ... Almost Christimas | 
|         |    329 //=============================== | 
|         |    330  | 
|         |    331 // I hope you had fun! | 
|         |    332  | 
|         |    333 // A function should do one thing, and only one thing. | 
|         |    334  | 
|         |    335 // Make your variables immutable, unless there's a good  | 
|         |    336 // reason not to. | 
|         |    337  | 
|         |    338 // I did it, but this is actually not a good reason: | 
|         |    339 // generating new labels | 
|         |    340 var counter = -1 | 
|         |    341  | 
|         |    342 def Fresh(x: String) = { | 
|         |    343   counter += 1 | 
|         |    344   x ++ "_" ++ counter.toString() | 
|         |    345 } | 
|         |    346  | 
|         |    347 Fresh("x") | 
|         |    348 Fresh("x") | 
|         |    349  | 
|         |    350  | 
|         |    351  | 
|         |    352 // You can be productive on Day 1, but the language is deep. | 
|         |    353 // | 
|         |    354 // http://scalapuzzlers.com | 
|         |    355 // | 
|         |    356 // http://www.latkin.org/blog/2017/05/02/when-the-scala-compiler-doesnt-help/ | 
|         |    357  | 
|         |    358 List(1, 2, 3) contains "your mom" | 
|         |    359  | 
|         |    360 // I like best about Scala that it lets me often write | 
|         |    361 // concise, readable code. And it hooks up with the  | 
|         |    362 // Isabelle theorem prover. | 
|         |    363  |