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