4 |
4 |
5 |
5 |
6 // Laziness with style |
6 // Laziness with style |
7 //===================== |
7 //===================== |
8 |
8 |
9 // The concept of lazy evaluation doesn’t really exist in |
9 // The concept of lazy evaluation doesn’t really |
10 // non-functional languages, but it is pretty easy to grasp. |
10 // exist in non-functional languages, but it is |
11 // Consider first |
11 // pretty easy to grasp. Consider first |
12 |
12 |
13 def square(x: Int) = x * x |
13 def square(x: Int) = x * x |
14 |
14 |
15 square(42 + 8) |
15 square(42 + 8) |
16 |
16 |
17 // this is called strict evaluation |
17 // this is called strict evaluation |
18 |
18 |
19 // pretty expensive operation |
19 // say we have a pretty expensive operation |
20 def peop(n: BigInt): Boolean = peop(n + 1) |
20 def peop(n: BigInt): Boolean = peop(n + 1) |
|
21 |
21 val a = "foo" |
22 val a = "foo" |
22 val b = "foo" |
23 val b = "foo" |
23 |
24 |
24 if (a == b || peop(0)) println("true") else println("false") |
25 if (a == b || peop(0)) println("true") else println("false") |
25 |
26 |
41 // primes: 2, 3, 5, 7, 9, 11, 13 .... |
42 // primes: 2, 3, 5, 7, 9, 11, 13 .... |
42 |
43 |
43 def generatePrimes (s: Stream[Int]): Stream[Int] = |
44 def generatePrimes (s: Stream[Int]): Stream[Int] = |
44 s.head #:: generatePrimes(s.tail.filter(_ % s.head != 0)) |
45 s.head #:: generatePrimes(s.tail.filter(_ % s.head != 0)) |
45 |
46 |
46 val primes: Stream[Int] = generatePrimes(Stream.from(2)) |
47 val primes = generatePrimes(Stream.from(2)) |
47 |
48 |
48 // the first 10 primes |
49 // the first 10 primes |
49 primes.take(10).toList |
50 primes.take(10).toList |
50 |
51 |
51 //primes.filter(_ > 100).take(2000).toList |
|
52 |
|
53 time_needed(1, primes.filter(_ > 100).take(3000).toList) |
52 time_needed(1, primes.filter(_ > 100).take(3000).toList) |
54 time_needed(1, primes.filter(_ > 100).take(3000).toList) |
53 time_needed(1, primes.filter(_ > 100).take(3000).toList) |
55 |
54 |
56 |
55 // a stream of successive numbers |
57 Stream.from(2) |
56 Stream.from(2) |
|
57 |
58 Stream.from(2).take(10) |
58 Stream.from(2).take(10) |
59 Stream.from(2).take(10).print |
59 Stream.from(2).take(10).print |
60 Stream.from(10).take(10).print |
60 Stream.from(10).take(10).print |
61 |
61 |
62 Stream.from(2).take(10).force |
62 Stream.from(2).take(10).force |
63 |
63 |
64 // itterative version of the Fibonacci numbers |
64 // iterative version of the Fibonacci numbers |
65 def fibIter(a: BigInt, b: BigInt): Stream[BigInt] = |
65 def fibIter(a: BigInt, b: BigInt): Stream[BigInt] = |
66 a #:: fibIter(b, a + b) |
66 a #:: fibIter(b, a + b) |
67 |
67 |
68 |
68 |
69 fibIter(1, 1).take(10).force |
69 fibIter(1, 1).take(10).force |
86 case class ALT(r1: Rexp, r2: Rexp) extends Rexp // alternative r1 + r2 |
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 |
87 case class SEQ(r1: Rexp, r2: Rexp) extends Rexp // sequence r1 . r2 |
88 case class STAR(r: Rexp) extends Rexp // star r* |
88 case class STAR(r: Rexp) extends Rexp // star r* |
89 |
89 |
90 |
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 |
91 // some convenience for typing in regular expressions |
98 import scala.language.implicitConversions |
92 import scala.language.implicitConversions |
99 import scala.language.reflectiveCalls |
93 import scala.language.reflectiveCalls |
100 |
94 |
101 def charlist2rexp(s: List[Char]): Rexp = s match { |
95 def charlist2rexp(s: List[Char]): Rexp = s match { |
105 } |
99 } |
106 implicit def string2rexp(s: String): Rexp = |
100 implicit def string2rexp(s: String): Rexp = |
107 charlist2rexp(s.toList) |
101 charlist2rexp(s.toList) |
108 |
102 |
109 |
103 |
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 { |
104 implicit def RexpOps (r: Rexp) = new { |
115 def | (s: Rexp) = ALT(r, s) |
105 def | (s: Rexp) = ALT(r, s) |
116 def % = STAR(r) |
106 def % = STAR(r) |
117 def ~ (s: Rexp) = SEQ(r, s) |
107 def ~ (s: Rexp) = SEQ(r, s) |
118 } |
108 } |
119 |
|
120 |
109 |
121 implicit def stringOps (s: String) = new { |
110 implicit def stringOps (s: String) = new { |
122 def | (r: Rexp) = ALT(s, r) |
111 def | (r: Rexp) = ALT(s, r) |
123 def | (r: String) = ALT(s, r) |
112 def | (r: String) = ALT(s, r) |
124 def % = STAR(s) |
113 def % = STAR(s) |
142 val number = sign ~ digit ~ digit.% |
131 val number = sign ~ digit ~ digit.% |
143 |
132 |
144 // task: enumerate exhaustively regular expression |
133 // task: enumerate exhaustively regular expression |
145 // starting from small ones towards bigger ones. |
134 // starting from small ones towards bigger ones. |
146 |
135 |
147 // 1st idea: enumerate them up to a level |
136 // 1st idea: enumerate them all in a Set |
|
137 // up to a level |
148 |
138 |
149 def enuml(l: Int, s: String) : Set[Rexp] = l match { |
139 def enuml(l: Int, s: String) : Set[Rexp] = l match { |
150 case 0 => Set(ZERO, ONE) ++ s.map(CHAR).toSet |
140 case 0 => Set(ZERO, ONE) ++ s.map(CHAR).toSet |
151 case n => |
141 case n => |
152 val rs = enuml(n - 1, s) |
142 val rs = enuml(n - 1, s) |
154 (for (r1 <- rs; r2 <- rs) yield ALT(r1, r2)) ++ |
144 (for (r1 <- rs; r2 <- rs) yield ALT(r1, r2)) ++ |
155 (for (r1 <- rs; r2 <- rs) yield SEQ(r1, r2)) ++ |
145 (for (r1 <- rs; r2 <- rs) yield SEQ(r1, r2)) ++ |
156 (for (r1 <- rs) yield STAR(r1)) |
146 (for (r1 <- rs) yield STAR(r1)) |
157 } |
147 } |
158 |
148 |
|
149 enuml(1, "a") |
159 enuml(1, "a").size |
150 enuml(1, "a").size |
160 enuml(2, "a").size |
151 enuml(2, "a").size |
161 enuml(3, "a").size // out of heap space |
152 enuml(3, "a").size |
|
153 enuml(4, "a").size // out of heap space |
162 |
154 |
163 |
155 |
164 def enum(rs: Stream[Rexp]) : Stream[Rexp] = |
156 def enum(rs: Stream[Rexp]) : Stream[Rexp] = |
165 rs #::: enum( (for (r1 <- rs; r2 <- rs) yield ALT(r1, r2)) #::: |
157 rs #::: enum( (for (r1 <- rs; r2 <- rs) yield ALT(r1, r2)) #::: |
166 (for (r1 <- rs; r2 <- rs) yield SEQ(r1, r2)) #::: |
158 (for (r1 <- rs; r2 <- rs) yield SEQ(r1, r2)) #::: |
167 (for (r1 <- rs) yield STAR(r1)) ) |
159 (for (r1 <- rs) yield STAR(r1)) ) |
168 |
160 |
169 |
161 |
170 enum(ZERO #:: ONE #:: "ab".toStream.map(CHAR)).take(200).force |
162 enum(ZERO #:: ONE #:: "ab".toStream.map(CHAR)).take(200).force |
171 enum(ZERO #:: ONE #:: "ab".toStream.map(CHAR)).take(200000).force |
163 enum(ZERO #:: ONE #:: "ab".toStream.map(CHAR)).take(5000000) |
172 |
164 |
173 |
165 |
174 val is = |
166 val is = |
175 (enum(ZERO #:: ONE #:: "ab".toStream.map(CHAR)) |
167 (enum(ZERO #:: ONE #:: "ab".toStream.map(CHAR)) |
176 .dropWhile(depth(_) < 3) |
168 .dropWhile(depth(_) < 3) |
323 |
315 |
324 |
316 |
325 |
317 |
326 |
318 |
327 |
319 |
328 // The End ... Almost Christimas |
320 // The End ... Almost Christmas |
329 //=============================== |
321 //=============================== |
330 |
322 |
331 // I hope you had fun! |
323 // I hope you had fun! |
332 |
324 |
333 // A function should do one thing, and only one thing. |
325 // A function should do one thing, and only one thing. |
334 |
326 |
335 // Make your variables immutable, unless there's a good |
327 // Make your variables immutable, unless there's a good |
336 // reason not to. |
328 // reason not to. |
337 |
329 |
338 // I did it, but this is actually not a good reason: |
330 // I did it, but this is actually not a good reason: |
339 // generating new labels |
331 // generating new labels: |
|
332 |
340 var counter = -1 |
333 var counter = -1 |
341 |
334 |
342 def Fresh(x: String) = { |
335 def Fresh(x: String) = { |
343 counter += 1 |
336 counter += 1 |
344 x ++ "_" ++ counter.toString() |
337 x ++ "_" ++ counter.toString() |