19 bcollatz(9.toBinaryString) |
84 bcollatz(9.toBinaryString) |
20 bcollatz(837799.toBinaryString) |
85 bcollatz(837799.toBinaryString) |
21 bcollatz(100000000000000000L.toBinaryString) |
86 bcollatz(100000000000000000L.toBinaryString) |
22 bcollatz(BigInt("1000000000000000000000000000000000000000000000000000000000000000000000000000").toString(2)) |
87 bcollatz(BigInt("1000000000000000000000000000000000000000000000000000000000000000000000000000").toString(2)) |
23 |
88 |
24 def conv(c: Char) : Int = c match { |
89 |
25 case '0' => 0 |
90 |
26 case '1' => 1 |
91 |
27 } |
92 // User-defined Datatypes |
28 |
93 //======================== |
29 def badds(s1: String, s2: String, carry: Int) : String = (s1, s2, carry) match { |
94 |
30 case ("", "", 1) => "1" |
95 abstract class Colour |
31 case ("", "", 0) => "" |
96 case class Red() extends Colour |
32 case (cs1, cs2, carry) => (conv(cs1.last) + conv(cs2.last) + carry) match { |
97 case class Green() extends Colour |
33 case 3 => badds(cs1.dropRight(1), cs2.dropRight(1), 1) + '1' |
98 case class Blue() extends Colour |
34 case 2 => badds(cs1.dropRight(1), cs2.dropRight(1), 1) + '0' |
99 |
35 case 1 => badds(cs1.dropRight(1), cs2.dropRight(1), 0) + '1' |
100 def fav_colour(c: Colour) : Boolean = c match { |
36 case 0 => badds(cs1.dropRight(1), cs2.dropRight(1), 0) + '0' |
101 case Red() => false |
37 } |
102 case Green() => true |
38 } |
103 case Blue() => false |
39 |
104 } |
40 def bcollatz2(s: String) : Long = (s.dropRight(1), s.last) match { |
105 |
41 case ("", '1') => 1 // we reached 1 |
106 |
42 case (rest, '0') => 1 + bcollatz2(rest) // even number => divide by two |
107 // actually colors can be written with "object", |
43 case (rest, '1') => 1 + bcollatz2(badds(s + '1', '0' + s, 0)) // odd number => s + '1' is 2 * s + 1 |
108 // because they do not take any arguments |
44 // add another s gives 3 * s + 1 |
|
45 } |
|
46 |
|
47 bcollatz2(9.toBinaryString) |
|
48 bcollatz2(837799.toBinaryString) |
|
49 bcollatz2(100000000000000000L.toBinaryString) |
|
50 bcollatz2(BigInt("1000000000000000000000000000000000000000000000000000000000000000000000000000").toString(2)) |
|
51 |
109 |
52 |
110 |
53 |
111 |
54 // Roman Numerals |
112 // Roman Numerals |
55 abstract class RomanDigit |
113 abstract class RomanDigit |
86 RomanNumeral2Int(List(I,X)) // 9 |
144 RomanNumeral2Int(List(I,X)) // 9 |
87 RomanNumeral2Int(List(M,C,M,L,X,X,I,X)) // 1979 |
145 RomanNumeral2Int(List(M,C,M,L,X,X,I,X)) // 1979 |
88 RomanNumeral2Int(List(M,M,X,V,I,I)) // 2017 |
146 RomanNumeral2Int(List(M,M,X,V,I,I)) // 2017 |
89 |
147 |
90 |
148 |
|
149 |
|
150 // another example |
|
151 //================= |
|
152 |
|
153 // Once upon a time, in a complete fictional country there were persons... |
|
154 |
|
155 abstract class Person |
|
156 case class King() extends Person |
|
157 case class Peer(deg: String, terr: String, succ: Int) extends Person |
|
158 case class Knight(name: String) extends Person |
|
159 case class Peasant(name: String) extends Person |
|
160 |
|
161 |
|
162 def title(p: Person): String = p match { |
|
163 case King() => "His Majesty the King" |
|
164 case Peer(deg, terr, _) => s"The ${deg} of ${terr}" |
|
165 case Knight(name) => s"Sir ${name}" |
|
166 case Peasant(name) => name |
|
167 } |
|
168 |
|
169 |
|
170 def superior(p1: Person, p2: Person): Boolean = (p1, p2) match { |
|
171 case (King(), _) => true |
|
172 case (Peer(_,_,_), Knight(_)) => true |
|
173 case (Peer(_,_,_), Peasant(_)) => true |
|
174 case (Peer(_,_,_), Clown()) => true |
|
175 case (Knight(_), Peasant(_)) => true |
|
176 case (Knight(_), Clown()) => true |
|
177 case (Clown(), Peasant(_)) => true |
|
178 case _ => false |
|
179 } |
|
180 |
|
181 val people = List(Knight("David"), |
|
182 Peer("Duke", "Norfolk", 84), |
|
183 Peasant("Christian"), |
|
184 King(), |
|
185 Clown()) |
|
186 |
|
187 println(people.sortWith(superior(_, _)).mkString(", ")) |
|
188 |
|
189 |
|
190 |
|
191 |
91 // Tail recursion |
192 // Tail recursion |
92 //================ |
193 //================ |
93 |
194 |
94 def my_contains(elem: Int, lst: List[Int]): Boolean = lst match { |
|
95 case Nil => false |
|
96 case x::xs => |
|
97 if (x == elem) true else my_contains(elem, xs) |
|
98 } |
|
99 |
|
100 my_contains(4, List(1,2,3)) |
|
101 my_contains(2, List(1,2,3)) |
|
102 |
|
103 my_contains(1000000, (1 to 1000000).toList) |
|
104 my_contains(1000001, (1 to 1000000).toList) |
|
105 |
|
106 |
|
107 //factorial V0.1 |
|
108 import scala.annotation.tailrec |
|
109 |
|
110 |
195 |
111 def fact(n: Long): Long = |
196 def fact(n: Long): Long = |
112 if (n == 0) 1 else n * fact(n - 1) |
197 if (n == 0) 1 else n * fact(n - 1) |
113 |
198 |
114 fact(10000) // produces a stackoverflow |
199 fact(10) //ok |
|
200 fact(10000) // produces a stackoverflow |
|
201 |
|
202 def factT(n: BigInt, acc: BigInt): BigInt = |
|
203 if (n == 0) acc else factT(n - 1, n * acc) |
|
204 |
|
205 factT(100000, 1) |
|
206 |
|
207 // there is a flag for ensuring a function is tail recursive |
|
208 import scala.annotation.tailrec |
115 |
209 |
116 @tailrec |
210 @tailrec |
117 def factT(n: BigInt, acc: BigInt): BigInt = |
211 def factT(n: BigInt, acc: BigInt): BigInt = |
118 if (n == 0) acc else factT(n - 1, n * acc) |
212 if (n == 0) acc else factT(n - 1, n * acc) |
119 |
213 |
120 |
214 |
121 println(factT(10000, 1)) |
215 |
122 |
216 // for tail-recursive functions the Scala compiler |
123 // the functions my_contains and factT are tail-recursive |
|
124 // you can check this with |
|
125 |
|
126 import scala.annotation.tailrec |
|
127 |
|
128 // and the annotation @tailrec |
|
129 |
|
130 // for tail-recursive functions the scala compiler |
|
131 // generates loop-like code, which does not need |
217 // generates loop-like code, which does not need |
132 // to allocate stack-space in each recursive |
218 // to allocate stack-space in each recursive |
133 // call; scala can do this only for tail-recursive |
219 // call; Scala can do this only for tail-recursive |
134 // functions |
220 // functions |
135 |
221 |
136 // consider the following "stupid" version of the |
222 |
137 // coin exchange problem: given some coins and a |
223 |
138 // total, what is the change can you get? |
224 // sudoku again |
139 |
225 |
140 val coins = List(4,5,6,8,10,13,19,20,21,24,38,39,40) |
226 val game0 = """.14.6.3.. |
141 |
227 |62...4..9 |
142 def first_positive[B](lst: List[Int], f: Int => Option[B]): Option[B] = lst match { |
228 |.8..5.6.. |
|
229 |.6.2....3 |
|
230 |.7..1..5. |
|
231 |5....9.6. |
|
232 |..6.2..3. |
|
233 |1..5...92 |
|
234 |..7.9.41.""".stripMargin.replaceAll("\\n", "") |
|
235 |
|
236 type Pos = (Int, Int) |
|
237 val EmptyValue = '.' |
|
238 val MaxValue = 9 |
|
239 |
|
240 val allValues = "123456789".toList |
|
241 val indexes = (0 to 8).toList |
|
242 |
|
243 |
|
244 def empty(game: String) = game.indexOf(EmptyValue) |
|
245 def isDone(game: String) = empty(game) == -1 |
|
246 def emptyPosition(game: String) = |
|
247 (empty(game) % MaxValue, empty(game) / MaxValue) |
|
248 |
|
249 |
|
250 def get_row(game: String, y: Int) = |
|
251 indexes.map(col => game(y * MaxValue + col)) |
|
252 def get_col(game: String, x: Int) = |
|
253 indexes.map(row => game(x + row * MaxValue)) |
|
254 |
|
255 def get_box(game: String, pos: Pos): List[Char] = { |
|
256 def base(p: Int): Int = (p / 3) * 3 |
|
257 val x0 = base(pos._1) |
|
258 val y0 = base(pos._2) |
|
259 val ys = (y0 until y0 + 3).toList |
|
260 (x0 until x0 + 3).toList.flatMap(x => ys.map(y => game(x + y * MaxValue))) |
|
261 } |
|
262 |
|
263 // this is not mutable!! |
|
264 def update(game: String, pos: Int, value: Char): String = |
|
265 game.updated(pos, value) |
|
266 |
|
267 def toAvoid(game: String, pos: Pos): List[Char] = |
|
268 (get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos)) |
|
269 |
|
270 def candidates(game: String, pos: Pos): List[Char] = |
|
271 allValues.diff(toAvoid(game,pos)) |
|
272 |
|
273 //candidates(game0, (0,0)) |
|
274 |
|
275 def pretty(game: String): String = |
|
276 "\n" + (game sliding (MaxValue, MaxValue) mkString "\n") |
|
277 |
|
278 // not tail recursive |
|
279 def search(game: String): List[String] = { |
|
280 if (isDone(game)) List(game) |
|
281 else { |
|
282 val cs = candidates(game, emptyPosition(game)) |
|
283 cs.map(c => search(update(game, empty(game), c))).toList.flatten |
|
284 } |
|
285 } |
|
286 |
|
287 // tail recursive version that searches |
|
288 // for all solution |
|
289 def searchT(games: List[String], sols: List[String]): List[String] = games match { |
|
290 case Nil => sols |
|
291 case game::rest => { |
|
292 if (isDone(game)) searchT(rest, game::sols) |
|
293 else { |
|
294 val cs = candidates(game, emptyPosition(game)) |
|
295 searchT(cs.map(c => update(game, empty(game), c)) ::: rest, sols) |
|
296 } |
|
297 } |
|
298 } |
|
299 |
|
300 // tail recursive version that searches |
|
301 // for a single solution |
|
302 def search1T(games: List[String]): Option[String] = games match { |
143 case Nil => None |
303 case Nil => None |
144 case x::xs => |
304 case game::rest => { |
145 if (x <= 0) first_positive(xs, f) |
305 if (isDone(game)) Some(game) |
146 else { |
306 else { |
147 val fx = f(x) |
307 val cs = candidates(game, emptyPosition(game)) |
148 if (fx.isDefined) fx else first_positive(xs, f) |
308 search1T(cs.map(c => update(game, empty(game), c)) ::: rest) |
|
309 } |
149 } |
310 } |
150 } |
311 } |
151 |
312 |
152 |
313 // game with multiple solutions |
153 import scala.annotation.tailrec |
314 val game3 = """.8...9743 |
154 |
315 |.5...8.1. |
155 def search(total: Int, coins: List[Int], cs: List[Int]): Option[List[Int]] = { |
316 |.1....... |
156 if (total < cs.sum) None |
317 |8....5... |
157 else if (cs.sum == total) Some(cs) |
318 |...8.4... |
158 else first_positive(coins, (c: Int) => search(total, coins, c::cs)) |
319 |...3....6 |
159 } |
320 |.......7. |
160 |
321 |.3.5...8. |
161 search(11, coins, Nil) |
322 |9724...5.""".stripMargin.replaceAll("\\n", "") |
162 search(111, coins, Nil) |
323 |
163 search(111111, coins, Nil) |
324 searchT(List(game3), List()).map(pretty) |
164 |
325 search1T(List(game3)).map(pretty) |
165 val junk_coins = List(4,-2,5,6,8,0,10,13,19,20,-3,21,24,38,39, 40) |
|
166 search(11, junk_coins, Nil) |
|
167 search(111, junk_coins, Nil) |
|
168 |
|
169 |
|
170 import scala.annotation.tailrec |
|
171 |
|
172 @tailrec |
|
173 def searchT(total: Int, coins: List[Int], |
|
174 acc_cs: List[List[Int]]): Option[List[Int]] = acc_cs match { |
|
175 case Nil => None |
|
176 case x::xs => |
|
177 if (total < x.sum) searchT(total, coins, xs) |
|
178 else if (x.sum == total) Some(x) |
|
179 else searchT(total, coins, coins.filter(_ > 0).map(_::x) ::: xs) |
|
180 } |
|
181 |
|
182 val start_acc = coins.filter(_ > 0).map(List(_)) |
|
183 searchT(11, junk_coins, start_acc) |
|
184 searchT(111, junk_coins, start_acc) |
|
185 searchT(111111, junk_coins, start_acc) |
|
186 |
326 |
187 // Moral: Whenever a recursive function is resource-critical |
327 // Moral: Whenever a recursive function is resource-critical |
188 // (i.e. works with large recursion depths), then you need to |
328 // (i.e. works with large recursion depths), then you need to |
189 // write it in tail-recursive fashion. |
329 // write it in tail-recursive fashion. |
190 // |
330 // |
191 // Unfortuantely, the Scala is because of current limitations in |
331 // Unfortuantely, Scala because of current limitations in |
192 // the JVM not as clever as other functional languages. It can |
332 // the JVM is not as clever as other functional languages. It can |
193 // only optimise "self-tail calls". This excludes the cases of |
333 // only optimise "self-tail calls". This excludes the cases of |
194 // multiple functions making tail calls to each other. Well, |
334 // multiple functions making tail calls to each other. Well, |
195 // nothing is perfect. |
335 // nothing is perfect. |
196 |
336 |
197 |
337 |
228 |
368 |
229 // Remember? |
369 // Remember? |
230 def first[A, B](xs: List[A], f: A => Option[B]): Option[B] = ... |
370 def first[A, B](xs: List[A], f: A => Option[B]): Option[B] = ... |
231 |
371 |
232 |
372 |
233 // polymorphic classes |
373 |
234 //(trees with some content) |
374 // Cool Stuff |
235 |
375 //============ |
236 abstract class Tree[+A] |
376 |
237 case class Node[A](elem: A, left: Tree[A], right: Tree[A]) extends Tree[A] |
377 |
238 case object Leaf extends Tree[Nothing] |
378 |
239 |
379 |
240 val t0 = Node('4', Node('2', Leaf, Leaf), Node('7', Leaf, Leaf)) |
380 // Implicits |
241 |
381 //=========== |
242 def insert[A](tr: Tree[A], n: A): Tree[A] = tr match { |
382 // |
243 case Leaf => Node(n, Leaf, Leaf) |
383 // For example adding your own methods to Strings: |
244 case Node(m, left, right) => |
384 // Imagine you want to increment strings, like |
245 if (n == m) Node(m, left, right) |
385 // |
246 else if (n < m) Node(m, insert(left, n), right) |
386 // "HAL".increment |
247 else Node(m, left, insert(right, n)) |
387 // |
248 } |
388 // you can avoid ugly fudges, like a MyString, by |
249 |
389 // using implicit conversions. |
250 |
390 |
251 // the A-type needs to be ordered |
391 |
252 |
392 implicit class MyString(s: String) { |
253 abstract class Tree[+A <% Ordered[A]] |
393 def increment = for (c <- s) yield (c + 1).toChar |
254 case class Node[A <% Ordered[A]](elem: A, left: Tree[A], |
394 } |
255 right: Tree[A]) extends Tree[A] |
395 |
256 case object Leaf extends Tree[Nothing] |
396 "HAL".increment |
257 |
397 |
258 |
|
259 def insert[A <% Ordered[A]](tr: Tree[A], n: A): Tree[A] = tr match { |
|
260 case Leaf => Node(n, Leaf, Leaf) |
|
261 case Node(m, left, right) => |
|
262 if (n == m) Node(m, left, right) |
|
263 else if (n < m) Node(m, insert(left, n), right) |
|
264 else Node(m, left, insert(right, n)) |
|
265 } |
|
266 |
|
267 |
|
268 val t1 = Node(4, Node(2, Leaf, Leaf), Node(7, Leaf, Leaf)) |
|
269 insert(t1, 3) |
|
270 |
|
271 val t2 = Node('b', Node('a', Leaf, Leaf), Node('f', Leaf, Leaf)) |
|
272 insert(t2, 'e') |
|
273 |
398 |
274 |
399 |
275 |
400 |
276 // Regular expressions - the power of DSLs in Scala |
401 // Regular expressions - the power of DSLs in Scala |
277 //================================================== |
402 //================================================== |
278 |
403 |
279 |
|
280 abstract class Rexp |
404 abstract class Rexp |
281 case object ZERO extends Rexp |
405 case object ZERO extends Rexp // nothing |
282 case object ONE extends Rexp |
406 case object ONE extends Rexp // the empty string |
283 case class CHAR(c: Char) extends Rexp |
407 case class CHAR(c: Char) extends Rexp // a character c |
284 case class ALT(r1: Rexp, r2: Rexp) extends Rexp // alternative r1 + r2 |
408 case class ALT(r1: Rexp, r2: Rexp) extends Rexp // alternative r1 + r2 |
285 case class SEQ(r1: Rexp, r2: Rexp) extends Rexp // sequence r1 r2 |
409 case class SEQ(r1: Rexp, r2: Rexp) extends Rexp // sequence r1 o r2 |
286 case class STAR(r: Rexp) extends Rexp // star r* |
410 case class STAR(r: Rexp) extends Rexp // star r* |
287 |
411 |
288 |
412 |
289 // (ab)* |
413 // (ab)* |
290 val r0 = STAR(SEQ(CHAR('a'), CHAR('b'))) |
414 val r0 = STAR(SEQ(CHAR('a'), CHAR('b'))) |