48 // some starting URLs for the crawler |
48 // some starting URLs for the crawler |
49 val startURL = """https://nms.kcl.ac.uk/christian.urban/""" |
49 val startURL = """https://nms.kcl.ac.uk/christian.urban/""" |
50 crawl(startURL, 2) |
50 crawl(startURL, 2) |
51 |
51 |
52 |
52 |
|
53 // User-defined Datatypes |
|
54 //======================== |
|
55 |
|
56 |
|
57 abstract class Colour |
|
58 case object Red extends Colour |
|
59 case object Green extends Colour |
|
60 case object Blue extends Colour |
|
61 |
|
62 def fav_colour(c: Colour) : Boolean = c match { |
|
63 case Red => false |
|
64 case Green => true |
|
65 case Blue => false |
|
66 } |
|
67 |
|
68 fav_colour(Green) |
|
69 |
|
70 |
|
71 // ... a tiny bit more useful: Roman Numerals |
|
72 |
|
73 abstract class RomanDigit |
|
74 case object I extends RomanDigit |
|
75 case object V extends RomanDigit |
|
76 case object X extends RomanDigit |
|
77 case object L extends RomanDigit |
|
78 case object C extends RomanDigit |
|
79 case object D extends RomanDigit |
|
80 case object M extends RomanDigit |
|
81 |
|
82 type RomanNumeral = List[RomanDigit] |
|
83 |
|
84 List(X,I) |
|
85 |
|
86 /* |
|
87 I -> 1 |
|
88 II -> 2 |
|
89 III -> 3 |
|
90 IV -> 4 |
|
91 V -> 5 |
|
92 VI -> 6 |
|
93 VII -> 7 |
|
94 VIII -> 8 |
|
95 IX -> 9 |
|
96 X -> X |
|
97 */ |
|
98 |
|
99 def RomanNumeral2Int(rs: RomanNumeral): Int = rs match { |
|
100 case Nil => 0 |
|
101 case M::r => 1000 + RomanNumeral2Int(r) |
|
102 case C::M::r => 900 + RomanNumeral2Int(r) |
|
103 case D::r => 500 + RomanNumeral2Int(r) |
|
104 case C::D::r => 400 + RomanNumeral2Int(r) |
|
105 case C::r => 100 + RomanNumeral2Int(r) |
|
106 case X::C::r => 90 + RomanNumeral2Int(r) |
|
107 case L::r => 50 + RomanNumeral2Int(r) |
|
108 case X::L::r => 40 + RomanNumeral2Int(r) |
|
109 case X::r => 10 + RomanNumeral2Int(r) |
|
110 case I::X::r => 9 + RomanNumeral2Int(r) |
|
111 case V::r => 5 + RomanNumeral2Int(r) |
|
112 case I::V::r => 4 + RomanNumeral2Int(r) |
|
113 case I::r => 1 + RomanNumeral2Int(r) |
|
114 } |
|
115 |
|
116 RomanNumeral2Int(List(I,V)) // 4 |
|
117 RomanNumeral2Int(List(I,I,I,I)) // 4 (invalid Roman number) |
|
118 RomanNumeral2Int(List(V,I)) // 6 |
|
119 RomanNumeral2Int(List(I,X)) // 9 |
|
120 RomanNumeral2Int(List(M,C,M,L,X,X,I,X)) // 1979 |
|
121 RomanNumeral2Int(List(M,M,X,V,I,I)) // 2017 |
|
122 |
|
123 |
|
124 // another example |
|
125 //================= |
|
126 |
|
127 // Once upon a time, in a complete fictional |
|
128 // country there were Persons... |
|
129 |
|
130 |
|
131 abstract class Person |
|
132 case object King extends Person |
|
133 case class Peer(deg: String, terr: String, succ: Int) extends Person |
|
134 case class Knight(name: String) extends Person |
|
135 case class Peasant(name: String) extends Person |
|
136 |
|
137 |
|
138 def title(p: Person): String = p match { |
|
139 case King => "His Majesty the King" |
|
140 case Peer(deg, terr, _) => s"The ${deg} of ${terr}" |
|
141 case Knight(name) => s"Sir ${name}" |
|
142 case Peasant(name) => name |
|
143 } |
|
144 |
|
145 def superior(p1: Person, p2: Person): Boolean = (p1, p2) match { |
|
146 case (King, _) => true |
|
147 case (Peer(_,_,_), Knight(_)) => true |
|
148 case (Peer(_,_,_), Peasant(_)) => true |
|
149 case (Peer(_,_,_), Clown) => true |
|
150 case (Knight(_), Peasant(_)) => true |
|
151 case (Knight(_), Clown) => true |
|
152 case (Clown, Peasant(_)) => true |
|
153 case _ => false |
|
154 } |
|
155 |
|
156 val people = List(Knight("David"), |
|
157 Peer("Duke", "Norfolk", 84), |
|
158 Peasant("Christian"), |
|
159 King, |
|
160 Clown) |
|
161 |
|
162 println(people.sortWith(superior).mkString("\n")) |
|
163 |
|
164 |
|
165 // String interpolations as patterns |
|
166 |
|
167 val date = "2000-01-01" |
|
168 val s"$year-$month-$day" = date |
|
169 |
|
170 def parse_date(date: String) = date match { |
|
171 case s"$year-$month-$day" => Some((year.toInt, month.toInt, day.toInt)) |
|
172 case s"$day/$month/$year" => Some((year.toInt, month.toInt, day.toInt)) |
|
173 case _ => None |
|
174 } |
|
175 |
|
176 |
|
177 |
53 |
178 |
54 // User-defined Datatypes and Pattern Matching |
179 // User-defined Datatypes and Pattern Matching |
55 //============================================= |
180 //============================================= |
|
181 |
|
182 |
56 |
183 |
57 abstract class Exp |
184 abstract class Exp |
58 case class N(n: Int) extends Exp // for numbers |
185 case class N(n: Int) extends Exp // for numbers |
59 case class Plus(e1: Exp, e2: Exp) extends Exp |
186 case class Plus(e1: Exp, e2: Exp) extends Exp |
60 case class Times(e1: Exp, e2: Exp) extends Exp |
187 case class Times(e1: Exp, e2: Exp) extends Exp |
320 jumps(List(1,3,6,1,0,9)).minBy(_.length) |
447 jumps(List(1,3,6,1,0,9)).minBy(_.length) |
321 jumps(List(2,3,1,1,2,4,2,0,1,1)).minBy(_.length) |
448 jumps(List(2,3,1,1,2,4,2,0,1,1)).minBy(_.length) |
322 |
449 |
323 |
450 |
324 |
451 |
325 |
452 // Tail Recursion |
|
453 //================ |
|
454 |
|
455 |
|
456 def fact(n: Long): Long = |
|
457 if (n == 0) 1 else n * fact(n - 1) |
|
458 |
|
459 fact(10) //ok |
|
460 fact(10000) // produces a stackoverflow |
|
461 |
|
462 def factT(n: BigInt, acc: BigInt): BigInt = |
|
463 if (n == 0) acc else factT(n - 1, n * acc) |
|
464 |
|
465 factT(10, 1) |
|
466 factT(100000, 1) |
|
467 |
|
468 // there is a flag for ensuring a function is tail recursive |
|
469 import scala.annotation.tailrec |
|
470 |
|
471 @tailrec |
|
472 def factT(n: BigInt, acc: BigInt): BigInt = |
|
473 if (n == 0) acc else factT(n - 1, n * acc) |
|
474 |
|
475 |
|
476 |
|
477 // for tail-recursive functions the Scala compiler |
|
478 // generates loop-like code, which does not need |
|
479 // to allocate stack-space in each recursive |
|
480 // call; Scala can do this only for tail-recursive |
|
481 // functions |
326 |
482 |
327 |
483 |
328 |
484 |
329 |
485 |
330 |
486 |